Merge branch 'main' into breaking_changes
# Conflicts: # BaseClasses.py # Mystery.py # WebHostLib/downloads.py # WebHostLib/models.py # WebHostLib/templates/macros.html # WebHostLib/upload.py # worlds/alttp/ItemPool.py # worlds/alttp/Main.py
This commit is contained in:
@@ -77,10 +77,14 @@ def register_session():
|
||||
session["_id"] = uuid4() # uniquely identify each session without needing a login
|
||||
|
||||
|
||||
@app.route('/tutorial/<string:game>/<string:file>/<string:lang>')
|
||||
def tutorial(game, file, lang):
|
||||
return render_template("tutorial.html", game=game, file=file, lang=lang)
|
||||
|
||||
|
||||
@app.route('/tutorial')
|
||||
@app.route('/tutorial/<string:lang>')
|
||||
def tutorial(lang='en'):
|
||||
return render_template(f"tutorial.html", lang=lang)
|
||||
def tutorial_landing():
|
||||
return render_template("tutorialLanding.html")
|
||||
|
||||
|
||||
@app.route('/player-settings')
|
||||
|
||||
@@ -29,8 +29,9 @@ def download_spoiler(seed_id):
|
||||
|
||||
|
||||
@app.route("/dl_raw_patch/<suuid:seed_id>/<int:player_id>")
|
||||
def download_raw_patch(seed_id, player_id):
|
||||
patch = select(patch for patch in Patch if patch.player_id == player_id and patch.seed.id == seed_id).first()
|
||||
def download_raw_patch(seed_id, player_id: int):
|
||||
patch = select(patch for patch in Patch if
|
||||
patch.player_id == player_id and patch.seed.id == seed_id).first()
|
||||
|
||||
if not patch:
|
||||
return "Patch not found"
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
const availableLanguages = {
|
||||
de: 'Deutsch',
|
||||
en: 'English',
|
||||
es: 'Español',
|
||||
fr: 'Français',
|
||||
};
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const tutorialWrapper = document.getElementById('tutorial-wrapper');
|
||||
new Promise((resolve, reject) => {
|
||||
@@ -21,27 +14,11 @@ window.addEventListener('load', () => {
|
||||
}
|
||||
resolve(ajax.responseText);
|
||||
};
|
||||
ajax.open('GET', `${window.location.origin}/static/assets/tutorial/tutorial_` +
|
||||
`${tutorialWrapper.getAttribute('data-language')}.md`, true);
|
||||
ajax.open('GET', `${window.location.origin}/static/assets/tutorial/` +
|
||||
`${tutorialWrapper.getAttribute('data-game')}/${tutorialWrapper.getAttribute('data-file')}_` +
|
||||
`${tutorialWrapper.getAttribute('data-lang')}.md`, true);
|
||||
ajax.send();
|
||||
}).then((results) => {
|
||||
// Build the language selector
|
||||
let currentLanguage = window.location.href.split('/').pop();
|
||||
if (Object.keys(availableLanguages).indexOf(currentLanguage) === -1) { currentLanguage = 'en' }
|
||||
const languageSelectorWrapper = document.createElement('div');
|
||||
languageSelectorWrapper.setAttribute('id', 'language-selector-wrapper')
|
||||
const languageSelector = document.createElement('select');
|
||||
languageSelector.setAttribute('id', 'language-selector');
|
||||
for (const lang of Object.keys(availableLanguages)) {
|
||||
const option = document.createElement('option');
|
||||
option.value = lang;
|
||||
option.innerText = availableLanguages[lang];
|
||||
if (lang === currentLanguage) { option.setAttribute('selected', '1'); }
|
||||
languageSelector.appendChild(option);
|
||||
}
|
||||
languageSelectorWrapper.appendChild(languageSelector);
|
||||
tutorialWrapper.appendChild(languageSelectorWrapper);
|
||||
|
||||
// Populate page with HTML generated from markdown
|
||||
tutorialWrapper.innerHTML += (new showdown.Converter()).makeHtml(results);
|
||||
adjustHeaderWidth();
|
||||
@@ -65,14 +42,10 @@ window.addEventListener('load', () => {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('language-selector').addEventListener('change', (event) => {
|
||||
console.info(window.location.hostname);
|
||||
window.location.href = `http://${window.location.hostname}/tutorial/${event.target.value}`;
|
||||
});
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
tutorialWrapper.innerHTML =
|
||||
`<h2>${error}</h2>
|
||||
`<h2>This page is out of logic!</h2>
|
||||
<h3>Click <a href="${window.location.origin}/tutorial">here</a> to return to safety.</h3>`;
|
||||
});
|
||||
});
|
||||
|
||||
75
WebHostLib/static/assets/tutorial/tutorials.json
Normal file
75
WebHostLib/static/assets/tutorial/tutorials.json
Normal file
@@ -0,0 +1,75 @@
|
||||
[
|
||||
{
|
||||
"gameTitle": "The Legend of Zelda: A Link to the Past",
|
||||
"tutorials": [
|
||||
{
|
||||
"name": "Multiworld Setup Tutorial",
|
||||
"description": "A guide to setting up the Archipelago ALttP software on your computer. This guide covers single-player, multiworld, and related software.",
|
||||
"files": [
|
||||
{
|
||||
"language": "English",
|
||||
"filename": "zelda3/multiworld_en.md",
|
||||
"link": "zelda3/multiworld/en",
|
||||
"authors": [
|
||||
"Farrak Kilhn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"language": "Deutsch",
|
||||
"filename": "zelda3/multiworld_de.md",
|
||||
"link": "zelda3/multiworld/de",
|
||||
"authors": [
|
||||
"Fischfilet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"language": "Español",
|
||||
"filename": "zelda3/multiworld_es.md",
|
||||
"link": "zelda3/multiworld/es",
|
||||
"authors": [
|
||||
"Edos"
|
||||
]
|
||||
},
|
||||
{
|
||||
"language": "Français",
|
||||
"filename": "zelda3/multiworld_fr.md",
|
||||
"link": "zelda3/multiworld/fr",
|
||||
"authors": [
|
||||
"Coxla"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MSU-1 Setup Tutorial",
|
||||
"description": "A guide to setting up MSU-1, which allows for custom in-game music.",
|
||||
"files": [
|
||||
{
|
||||
"language": "English",
|
||||
"filename": "zelda3/msu1_en.md",
|
||||
"link": "zelda3/msu1/en",
|
||||
"authors": [
|
||||
"Farrak Kilhn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"language": "Español",
|
||||
"filename": "zelda3/msu1_es.md",
|
||||
"link": "zelda3/msu1/es",
|
||||
"authors": [
|
||||
"Edos"
|
||||
]
|
||||
},
|
||||
{
|
||||
"language": "Français",
|
||||
"filename": "msu1_fr.md",
|
||||
"link": "zelda3/msu1/fr",
|
||||
"authors": [
|
||||
"Coxla"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
76
WebHostLib/static/assets/tutorial/zelda3/msu1_en.md
Normal file
76
WebHostLib/static/assets/tutorial/zelda3/msu1_en.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# MSU-1 Setup Guide
|
||||
|
||||
## What is MSU-1?
|
||||
MSU-1 allows for the use of custom in-game music. It works on original hardware, the SuperNT, and certain emulators.
|
||||
This guide will explain how to find custom music packages, often called MSU packs, and how to configure
|
||||
them for use with original hardware, the SuperNT, and the snes9x emulator.
|
||||
|
||||
## Where to find MSU Packs
|
||||
MSU packs are constantly in development. You can find a list of completed packs, as well as in-development packs on
|
||||
[this Google Spreadsheet](https://docs.google.com/spreadsheets/d/1XRkR4Xy6S24UzYkYBAOv-VYWPKZIoUKgX04RbjF128Q).
|
||||
|
||||
## What an MSU pack should look like
|
||||
MSU packs contain many files, most of which are the music files which will be used when playing the game. These files
|
||||
should be named similarly, with a hyphenated number at the end, and with a `.pcm` extension. It does not matter what
|
||||
each music file is named, so long as they all follow the same pattern. The most popular filename you will find is
|
||||
`alttp_msu-X.pcm`, where X is replaced by a number.
|
||||
|
||||
There is one other type of file you should find inside an MSU pack's folder. This file indicates to the hardware or
|
||||
to the emulator that MSU should be enabled for this game. This file should be named similarly to the other files in
|
||||
the folder, but will have a `.msu` extension and be 0 KB in size.
|
||||
|
||||
A short example of the contents of an MSU pack folder are as follows:
|
||||
```
|
||||
List of files inside an MSU pack folder:
|
||||
alttp_msu.msu
|
||||
alttp_msu-1.pcm
|
||||
alttp_msu-2.pcm
|
||||
...
|
||||
alttp_msu-34.pcm
|
||||
```
|
||||
|
||||
## How to use an MSU Pack
|
||||
In all cases, you must rename your ROM file to match the pattern of names inside your MSU pack's folder, then place
|
||||
your ROM file inside that folder.
|
||||
|
||||
This will cause the folder contents to look like the following:
|
||||
```
|
||||
List of files inside an MSU pack folder:
|
||||
alttp_msu.msu
|
||||
alttp_msu.sfc <-- Add your ROM file
|
||||
alttp_msu-1.pcm
|
||||
alttp_msu-2.pcm
|
||||
...
|
||||
alttp_msu-34.pcm
|
||||
```
|
||||
|
||||
### With snes9x
|
||||
1. Load the ROM file from snes9x.
|
||||
|
||||
### With SD2SNES / FXPak on original hardware
|
||||
1. Load the MSU pack folder onto your SD2SNES / FXPak.
|
||||
2. Navigate into the MSU pack folder and load your ROM.
|
||||
|
||||
### With SD2SNES / FXPak on SuperNT
|
||||
1. Load the MSU pack folder onto your SD2SNES / FXPak.
|
||||
2. Power on your SuperNT and navigate to the `Settings` menu.
|
||||
3. Enter the `Audio` settings.
|
||||
4. Check the box marked `Cartridge Audio Enable.`
|
||||
5. Navigate back to the previous menu.
|
||||
6. Choose `Save/Clear Settings`.
|
||||
7. Choose `Save Settings`.
|
||||
8. Choose `Run Cartridge` from the main menu.
|
||||
9. Navigate into your MSU pack folder and load your ROM.
|
||||
|
||||
## A word of caution to streamers
|
||||
Many MSU packs use copyrighted music which is not permitted for use on platforms like Twitch and YouTube.
|
||||
If you choose to stream music from an MSU pack, please ensure you have permission to do so. If you stream
|
||||
music which has not been licensed to you, or licensed for use in a stream in general, your VOD may be muted.
|
||||
In the worst case, you may receive a DMCA take-down notice. Please be careful to only stream music for which
|
||||
you have the rights to do so.
|
||||
|
||||
##### Stream-safe MSU packs
|
||||
Below is a list of MSU packs which, so far as we know, are safe to stream. More will be added to this list as
|
||||
we learn of them. If you know of any we missed, please let us know!
|
||||
- Vanilla Game Music
|
||||
- [Smooth McGroove](https://drive.google.com/open?id=1JDa1jCKg5hG0Km6xNpmIgf4kDMOxVp3n)
|
||||
74
WebHostLib/static/assets/tutorial/zelda3/msu1_es.md
Normal file
74
WebHostLib/static/assets/tutorial/zelda3/msu1_es.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# MSU-1 Guía de instalación
|
||||
|
||||
## Que es MSU-1?
|
||||
MSU-1 permite el uso de música personalizada durante el juego. Funciona en hardware original, la SuperNT, y algunos emuladores.
|
||||
Esta guiá explicará como encontrar los packs de música personalizada, comúnmente llamados pack MSU, y como configurarlos
|
||||
para su uso en hardware original, la SuperNT, and el emulador snes9x.
|
||||
|
||||
## Donde encontrar packs MSU
|
||||
Los packs MSU están constantemente en desarrollo. Puedes encontrar una lista de pack completos, al igual que packs en desarrollo en
|
||||
[esta hoja de calculo Google](https://docs.google.com/spreadsheets/d/1XRkR4Xy6S24UzYkYBAOv-VYWPKZIoUKgX04RbjF128Q).
|
||||
|
||||
## Que pinta debe tener un pack MSU
|
||||
Los packs MSU contienen muchos ficheros, la mayoria de los cuales son los archivos de música que se usaran durante el juego. Estos ficheros
|
||||
deben tener un nombre similar, con un guión seguido por un número al final, y tienen extensión`.pcm`. No importa como se llame
|
||||
cada archivo de música, siempre y cuando todos sigan el mismo patrón. El nombre más popular es
|
||||
`alttp_msu-X.pcm`, donde X es un número.
|
||||
|
||||
Hay otro tipo de fichero que deberias encontrar en el directorio de un pack MSU. Este archivo indica al hardware o
|
||||
emulador que MSU debe ser activado para este juego. El fichero tiene un nombre similar al resto, pero tiene como extensión `.msu` y su tamaño es 0 KB.
|
||||
|
||||
Un pequeño ejemplo de los contenidos de un directorio que contiene un pack MSU:
|
||||
```
|
||||
Lista de ficheros dentro de un directorio de pack MSU:
|
||||
alttp_msu.msu
|
||||
alttp_msu-1.pcm
|
||||
alttp_msu-2.pcm
|
||||
...
|
||||
alttp_msu-34.pcm
|
||||
```
|
||||
|
||||
## Como usar un pack MSU
|
||||
En todos los casos, debes renombrar tu fichero de ROM para que coincida con el resto de nombres de fichero del directorio, y copiar/pegar tu fichero rom
|
||||
dentro de dicho directorio.
|
||||
|
||||
Esto hara que los contenidos del directorio sean los siguientes:
|
||||
```
|
||||
Lista de ficheros dentro del directorio de pack MSU:
|
||||
alttp_msu.msu
|
||||
alttp_msu.sfc <-- Tu fichero rom añadido
|
||||
alttp_msu-1.pcm
|
||||
alttp_msu-2.pcm
|
||||
...
|
||||
alttp_msu-34.pcm
|
||||
```
|
||||
|
||||
### Con snes9x
|
||||
1. Carga el fichero de rom en snes9x.
|
||||
|
||||
### Con SD2SNES / FXPak en hardware original
|
||||
1. Carga tu directorio de pack MSU en tu SD2SNES / FXPak.
|
||||
2. Navega hasta el directorio de pack MSU y carga la ROM
|
||||
|
||||
### Con SD2SNES / FXPak en SuperNT
|
||||
1. Carga tu directorio de pack MSU en tu SD2SNES / FXPak.
|
||||
2. Enciende tu SuperNT y navega al menú `Settings`.
|
||||
3. Entra en la opcion `Audio`.
|
||||
4. Activa la caja `Cartridge Audio Enable.`
|
||||
5. Navega al menú anterior
|
||||
6. Elije `Save/Clear Settings`.
|
||||
7. Elije `Save Settings`.
|
||||
8. Elije `Run Cartridge` en el menú principal.
|
||||
9. Navega hasta el directorio de pack MSU y carga la ROM
|
||||
|
||||
## Aviso a streamers
|
||||
Muchos packs MSU usan música con derechos de autor la cual no esta permitido su uso en plataformas como Twitch o YouTube.
|
||||
Si elijes hacer stream de dicha música, tu VOD puede ser silenciado. En el peor caso, puedes recibir una orden de eliminación DMCA.
|
||||
Por favor, tened cuidado y solo streamear música para la cual tengas los derechos para hacerlo.
|
||||
|
||||
##### Packs MSU seguros para Stream
|
||||
A continuación enumeramos los packs MSU que, packs which, por lo que sabemos, son seguros para vuestras retransmisiones. Se iran añadiendo mas conforme
|
||||
vayamos enterandonos. Si sabes alguno que podamos haber olvidado, por favor haznoslo saber!
|
||||
- Musica del juego original
|
||||
- [Smooth McGroove](https://drive.google.com/open?id=1JDa1jCKg5hG0Km6xNpmIgf4kDMOxVp3n)
|
||||
|
||||
68
WebHostLib/static/assets/tutorial/zelda3/msu1_fr.md
Normal file
68
WebHostLib/static/assets/tutorial/zelda3/msu1_fr.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Guide d'installation de MSU-1
|
||||
|
||||
## Qu'est-ce que MSU-1 ?
|
||||
MSU-1 permet l'utilisation de musiques en jeu personnalisées. Cela fonctionne sur une console originale, sur SuperNT, et sur certains émulateurs.
|
||||
Ce guide explique comment trouver des packs de musiques personnalisées, couremment appelées packs MSU, et comment les configurer
|
||||
pour les utiliser sur console, sur SuperNT et sur l'émulateur snes9x.
|
||||
|
||||
## Où trouver des packs MSU
|
||||
Les packs MSU sont constamment en développement. Vous pouvez trouver une liste de packs complétés, ainsi que des packs en développement sur
|
||||
[cette feuille de calcul Google](https://docs.google.com/spreadsheets/d/1XRkR4Xy6S24UzYkYBAOv-VYWPKZIoUKgX04RbjF128Q).
|
||||
|
||||
## A quoi ressemble un pack MSU
|
||||
Les packs MSU contiennent beaucoup de fichiers, la plupart étant des fichiers musicaux qui seront utilisés en cours de jeu. Ces fichiers
|
||||
doivent être nommés de façon similaire, avec un nombre derrière le tiret, puis l'extension `.pcm`. Le nom de chaque fichier
|
||||
n'importe pas, du moment qu'ils suivent tous le même motif. Le nom le plus populaire que vous verrez est
|
||||
`alttp_msu-X.pcm`, où X est remplacé par un nombre.
|
||||
|
||||
Il existe un autre type de fichier que vous devriez trouver dans le dossier d'un pack MSU. Ce fichier indique au matériel
|
||||
ou à l'émulateur que MSU doit être activé pour ce jeu. Ce fichier doit être nommé de façon similaires aux autres dans
|
||||
le dossier, mais il aura une extension `.msu` et pèsera 0 KB.
|
||||
|
||||
Voici un exemple de ce à quoi ressemble le dossier d'un pack MSU :
|
||||
```
|
||||
Liste des fichiers dans le dossier d'un pack MSU :
|
||||
alttp_msu.msu
|
||||
alttp_msu-1.pcm
|
||||
alttp_msu-2.pcm
|
||||
...
|
||||
alttp_msu-34.pcm
|
||||
```
|
||||
|
||||
## Comment utiliser un pack MSU
|
||||
Dans tous les cas, vosu devez renommer votre fichier ROM pour qu'il corresponde au même motif que les autres fichiers dans le dossier du pack MSU,
|
||||
ensuite vous placez votre fichier ROM dans ce dossier.
|
||||
|
||||
Le contenu du dossier ressemblera alors à ceci :
|
||||
```
|
||||
Liste des fichiers dans le dossier d'un pack MSU :
|
||||
alttp_msu.msu
|
||||
alttp_msu.sfc <-- Ajoutez votre fichier ROM
|
||||
alttp_msu-1.pcm
|
||||
alttp_msu-2.pcm
|
||||
...
|
||||
alttp_msu-34.pcm
|
||||
```
|
||||
|
||||
### Avec snes9x
|
||||
1. Chargez le fichier ROM depuis snes9x.
|
||||
|
||||
### Avec un SD2SNES / FXPak sur une console originale
|
||||
1. Mettez le dossier du pack MSU avec la ROM sur votre SD2SNES / FXPak.
|
||||
2. Naviguez vers ce dossier et chargez votre ROM.
|
||||
|
||||
### Avec un SD2SNES / FXPak sur SuperNT
|
||||
1. Mettez le dossier du pack MSU avec la ROM sur votre SD2SNES / FXPak.
|
||||
2. Allumez votre SuperNT et naviguez vers le menu `Settings` (paramètres).
|
||||
3. Entrez dans les paramètres `Audio`.
|
||||
4. Cochez la case marquée `Cartridge Audio Enable` (activer l'audio de cartouche).
|
||||
5. Retournez dans le menu précédent.
|
||||
6. Choisissez `Save/Clear Settings` (sauvegarder/effacer les paramètres).
|
||||
7. Choisissez `Save Settings` (sauvegarder les paramètres).
|
||||
8. Choisissez `Run Cartridge` (lancer une cartouche) depuis le menu principal.
|
||||
9. Naviguez vers le dossier du pack MSU et chargez votre ROM.
|
||||
|
||||
## Avertissement pour les streamers
|
||||
Beaucoup de packs MSU utilisent des musiques copyrightées ce qui n'est pas permis sur des plateformes comme Twitch et YouTube.
|
||||
Si vous choisissez de streamer des musiques copyrightées, votre VOD sera peut-être rendue muette. Dans le pire des cas, vous pourriez recevoir
|
||||
une plainte DMCA pour faire retirer la vidéo. Faites attention à streamer uniquement des musiques pour lesquelles vous avez le droit.
|
||||
77
WebHostLib/static/assets/tutorial/zelda3/plando_en.md
Normal file
77
WebHostLib/static/assets/tutorial/zelda3/plando_en.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# A Link to the Past Randomizer Plando Guide
|
||||
|
||||
## Configuration
|
||||
1. Plando features have to be enabled first, before they can be used (opt-in).
|
||||
2. To do so, go to your installation directory (Windows default: C:\ProgramData\BerserkerMultiWorld),
|
||||
then open the host.yaml file therein with a text editor.
|
||||
3. In it, you're looking for the option key "plando_options",
|
||||
to enable all plando modules you can set the value to "bosses, items, texts, connections"
|
||||
|
||||
## Modules
|
||||
|
||||
### Bosses
|
||||
|
||||
- This module is enabled by default and available to be used on
|
||||
[https://archipelago.gg/generate](https://archipelago.gg/generate)
|
||||
- Plando versions of boss shuffles can be added like any other boss shuffle option in a yaml and weighted.
|
||||
- Boss Plando works as a list of instructions from left to right, if any arenas are empty at the end,
|
||||
it defaults to vanilla
|
||||
- Instructions are separated by a semicolon
|
||||
- Available Instructions:
|
||||
- Direct Placement:
|
||||
- Example: "Eastern Palace-Trinexx"
|
||||
- Takes a particular Arena and particular boss, then places that boss into that arena
|
||||
- Ganons Tower has 3 placements, "Ganons Tower Top", "Ganons Tower Middle" and "Ganons Tower Bottom"
|
||||
- Boss Placement:
|
||||
- Example: "Trinexx"
|
||||
- Takes a particular boss and places that boss in any remaining slots in which this boss can function.
|
||||
- In this example, it would fill Desert Palace, but not Tower of Hera.
|
||||
- Boss Shuffle:
|
||||
- Example: "simple"
|
||||
- Runs a particular boss shuffle mode to finish construction instead of vanilla placement, typically used as a last instruction.
|
||||
- [Available Bosses](https://github.com/Berserker66/MultiWorld-Utilities/blob/65fa39df95c90c9b66141aee8b16b7e560d00819/Bosses.py#L135)
|
||||
- [Available Arenas](https://github.com/Berserker66/MultiWorld-Utilities/blob/65fa39df95c90c9b66141aee8b16b7e560d00819/Bosses.py#L186)
|
||||
|
||||
#### Examples:
|
||||
```yaml
|
||||
boss_shuffle:
|
||||
Turtle Rock-Trinexx;basic: 1
|
||||
full: 2
|
||||
Mothula: 3
|
||||
Ganons Tower Bottom-Kholdstare;Trinexx;Kholdstare: 4
|
||||
```
|
||||
1. Would be basic boss shuffle but prevent Trinexx from appearing outside of Turtle Rock,
|
||||
as there's only one Trinexx in the pool
|
||||
2. Regular full boss shuffle. With a 2 in 10 chance to occur.
|
||||
3. A Mothula Singularity, as Mothula works in any arena.
|
||||
4. A Trinexx -> Kholdstare Singularity that prevents ice Trinexx in GT
|
||||
|
||||
|
||||
|
||||
### Text
|
||||
- This module is disabled by default.
|
||||
- Has the options "text", "at" and "percentage"
|
||||
- percentage is the percentage chance for this text to be placed, can be omitted entirely for 100%
|
||||
- text is the text to be placed.
|
||||
- can be weighted.
|
||||
- \n is a newline.
|
||||
- @ is the entered player's name.
|
||||
- Warning: Text Mapper does not support full unicode.
|
||||
- [Alphabet](https://github.com/Berserker66/MultiWorld-Utilities/blob/65fa39df95c90c9b66141aee8b16b7e560d00819/Text.py#L756)
|
||||
- at is the location within the game to attach the text to.
|
||||
- can be weighted.
|
||||
- [List of targets](https://github.com/Berserker66/MultiWorld-Utilities/blob/65fa39df95c90c9b66141aee8b16b7e560d00819/Text.py#L1498)
|
||||
|
||||
#### Example
|
||||
```yaml
|
||||
plando_texts:
|
||||
- text: "This is a plando.\nYou've been warned."
|
||||
at:
|
||||
uncle_leaving_text: 1
|
||||
uncle_dying_sewer: 1
|
||||
percentage: 50
|
||||
```
|
||||

|
||||
This has a 50% chance to trigger at all, if it does,
|
||||
it throws a coin between "uncle_leaving_text" and "uncle_dying_sewer", then places the text
|
||||
"This is a plando.\nYou've been warned." at that location.
|
||||
71
WebHostLib/static/assets/tutorialLanding.js
Normal file
71
WebHostLib/static/assets/tutorialLanding.js
Normal file
@@ -0,0 +1,71 @@
|
||||
const showError = () => {
|
||||
const tutorial = document.getElementById('tutorial-landing');
|
||||
document.getElementById('page-title').innerText = 'This page is out of logic!';
|
||||
tutorial.removeChild(document.getElementById('loading'));
|
||||
const userMessage = document.createElement('h3');
|
||||
const homepageLink = document.createElement('a');
|
||||
homepageLink.innerText = 'Click here';
|
||||
homepageLink.setAttribute('href', '/');
|
||||
userMessage.append(homepageLink);
|
||||
userMessage.append(' to go back to safety!');
|
||||
tutorial.append(userMessage);
|
||||
};
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const ajax = new XMLHttpRequest();
|
||||
ajax.onreadystatechange = () => {
|
||||
if (ajax.readyState !== 4) { return; }
|
||||
const tutorialDiv = document.getElementById('tutorial-landing');
|
||||
if (ajax.status !== 200) { return showError(); }
|
||||
|
||||
try {
|
||||
const games = JSON.parse(ajax.responseText);
|
||||
games.forEach((game) => {
|
||||
const gameTitle = document.createElement('h2');
|
||||
gameTitle.innerText = game.gameTitle;
|
||||
tutorialDiv.appendChild(gameTitle);
|
||||
|
||||
game.tutorials.forEach((tutorial) => {
|
||||
const tutorialName = document.createElement('h3');
|
||||
tutorialName.innerText = tutorial.name;
|
||||
tutorialDiv.appendChild(tutorialName);
|
||||
|
||||
const tutorialDescription = document.createElement('p');
|
||||
tutorialDescription.innerText = tutorial.description;
|
||||
tutorialDiv.appendChild(tutorialDescription);
|
||||
|
||||
const intro = document.createElement('p');
|
||||
intro.innerText = 'This guide is available in the following languages:';
|
||||
tutorialDiv.appendChild(intro);
|
||||
|
||||
const fileList = document.createElement('ul');
|
||||
tutorial.files.forEach((file) => {
|
||||
const listItem = document.createElement('li');
|
||||
const anchor = document.createElement('a');
|
||||
anchor.innerText = file.language;
|
||||
anchor.setAttribute('href', `${window.location.origin}/tutorial/${file.link}`);
|
||||
listItem.appendChild(anchor);
|
||||
|
||||
listItem.append(' by ');
|
||||
for (let author of file.authors) {
|
||||
listItem.append(author);
|
||||
if (file.authors.indexOf(author) !== (file.authors.length -1)) {
|
||||
listItem.append(', ');
|
||||
}
|
||||
}
|
||||
|
||||
fileList.appendChild(listItem);
|
||||
});
|
||||
tutorialDiv.appendChild(fileList);
|
||||
});
|
||||
});
|
||||
|
||||
tutorialDiv.removeChild(document.getElementById('loading'));
|
||||
} catch (error) {
|
||||
showError();
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
ajax.open('GET', `${window.location.origin}/static/assets/tutorial/tutorials.json`, true);
|
||||
ajax.send();
|
||||
});
|
||||
@@ -1017,7 +1017,7 @@
|
||||
"expert": {
|
||||
"keyString": "enemy_health.expert",
|
||||
"friendlyName": "Armor-Plated",
|
||||
"description": "Enemies will be very heard to defeat.",
|
||||
"description": "Enemies will be very hard to defeat.",
|
||||
"defaultValue": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ html{
|
||||
color: #eeffeb;
|
||||
}
|
||||
|
||||
#tutorial-wrapper p{
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#tutorial-wrapper a{
|
||||
color: #ffef00;
|
||||
}
|
||||
@@ -90,6 +94,7 @@ html{
|
||||
}
|
||||
|
||||
#tutorial-wrapper pre{
|
||||
margin-top: 0;
|
||||
padding: 0.5rem 0.25rem;
|
||||
background-color: #ffeeab;
|
||||
border: 1px solid #9f916a;
|
||||
|
||||
106
WebHostLib/static/styles/tutorialLanding.css
Normal file
106
WebHostLib/static/styles/tutorialLanding.css
Normal file
@@ -0,0 +1,106 @@
|
||||
html{
|
||||
background-image: url('../static/backgrounds/grass/grass-0007-large.png');
|
||||
background-repeat: repeat;
|
||||
background-size: 650px 650px;
|
||||
}
|
||||
|
||||
#tutorial-landing{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 70rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
border-radius: 8px;
|
||||
padding: 1rem 1rem 3rem;
|
||||
color: #eeffeb;
|
||||
}
|
||||
|
||||
#tutorial-landing p{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#tutorial-landing a{
|
||||
color: #ffef00;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#tutorial-landing h1{
|
||||
font-size: 2.5rem;
|
||||
font-weight: normal;
|
||||
border-bottom: 1px solid #ffffff;
|
||||
width: 100%;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #ffffff;
|
||||
text-shadow: 1px 1px 4px #000000;
|
||||
}
|
||||
|
||||
#tutorial-landing h2{
|
||||
font-size: 2rem;
|
||||
font-weight: normal;
|
||||
border-bottom: 1px solid #ffffff;
|
||||
width: 100%;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #ffe993;
|
||||
text-transform: lowercase;
|
||||
text-shadow: 1px 1px 2px #000000;
|
||||
}
|
||||
|
||||
#tutorial-landing h3{
|
||||
font-size: 1.70rem;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#tutorial-landing h4{
|
||||
font-size: 1.5rem;
|
||||
font-weight: normal;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#tutorial-landing h5{
|
||||
font-size: 1.25rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#tutorial-landing h6{
|
||||
font-size: 1.25rem;
|
||||
font-weight: normal;
|
||||
color: #434343;
|
||||
}
|
||||
|
||||
#tutorial-landing h3, #tutorial-landing h4, #tutorial-landing h5,#tutorial-landing h6{
|
||||
color: #ffffff;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
#tutorial-landing ul{
|
||||
|
||||
}
|
||||
|
||||
#tutorial-landing ol{
|
||||
|
||||
}
|
||||
|
||||
#tutorial-landing li{
|
||||
|
||||
}
|
||||
|
||||
#tutorial-landing pre{
|
||||
margin-top: 0;
|
||||
padding: 0.5rem 0.25rem;
|
||||
background-color: #ffeeab;
|
||||
border: 1px solid #9f916a;
|
||||
border-radius: 6px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
#tutorial-landing code{
|
||||
background-color: #ffeeab;
|
||||
border-radius: 4px;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
color: #000000;
|
||||
}
|
||||
@@ -8,12 +8,12 @@
|
||||
<a href="/" id="site-title">
|
||||
<img src="/favicon.ico" alt="Favicon" />
|
||||
</a>
|
||||
<a href="/">multiworld randomizer</a>
|
||||
<a href="/">archipelago</a>
|
||||
</div>
|
||||
<div id="base-header-right">
|
||||
<a href="/player-settings">start game</a>
|
||||
<a href="/uploads">host game</a>
|
||||
<a href="/tutorial">setup guide</a>
|
||||
<a href="/tutorial">setup guides</a>
|
||||
<a href="/generate">upload config</a>
|
||||
<a href="https://discord.gg/8Z65BR2">discord</a>
|
||||
</div>
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
<div id="host-game" class="grass-island {% if rooms %}wider{% endif %}">
|
||||
<h1>Host Game</h1>
|
||||
<p>
|
||||
To host a game, you need to upload a .multidata file or a .zip file<br />
|
||||
created by the multiworld generator.
|
||||
This page allows you to host a game which was not generated by the website. For example, if you have
|
||||
generated a doors game on your own computer, you may upload the zip file created by the generator to
|
||||
host the game here. This will also provide the tracker, and the ability for your players to download
|
||||
their patch files.
|
||||
<br /><br />
|
||||
In addition to a zip file created by the generator, you may upload a multidata file here as well.
|
||||
</p>
|
||||
<div id="host-game-form-wrapper">
|
||||
<form id="host-game-form" method="post" enctype="multipart/form-data">
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
later,
|
||||
you can simply refresh this page and the server will be started again.<br>
|
||||
{% if room.last_port %}
|
||||
You can connect to this room by using '/connect berserkermulti.world:{{ room.last_port }}'
|
||||
You can connect to this room by using '/connect archipelago.gg:{{ room.last_port }}'
|
||||
in the <a href="https://github.com/Berserker66/MultiWorld-Utilities/releases">client</a>.<br>{% endif %}
|
||||
{{ macros.list_patches_room(room.seed.patches, room) }}
|
||||
{{ macros.list_patches_room(room) }}
|
||||
{% if room.owner == session["_id"] %}
|
||||
<form method=post>
|
||||
<div class="form-group">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div id="landing-links">
|
||||
<a href="/player-settings" id="player-settings-button">start<br />playing</a>
|
||||
<a href="/uploads" id="uploads-button">host<br />game</a>
|
||||
<a href="/tutorial" id="setup-guide-button">setup guide</a>
|
||||
<a href="/tutorial" id="setup-guide-button">setup guides</a>
|
||||
<a href="/generate" id="generate-button">upload config</a>
|
||||
<a href="https://discord.gg/8Z65BR2" id="discord-button">discord</a>
|
||||
</div>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
{{ caller() }}
|
||||
</ul>
|
||||
{%- endmacro %}
|
||||
{% macro list_patches_room(patches, room) %}
|
||||
{% if patches %}
|
||||
{% macro list_patches_room(room) %}
|
||||
{% if room.seed.patches %}
|
||||
<ul>
|
||||
{% for patch in patches|list|sort(attribute="player") %}
|
||||
<li><a href="{{ url_for("download_patch", patch_id=patch.id, room_id=room.id) }}">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
{% block head %}
|
||||
{% include 'header/grassHeader.html' %}
|
||||
<title>Setup Tutorial</title>
|
||||
<title>Archipelago</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/tutorial.css") }}" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js"
|
||||
integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw=="
|
||||
@@ -11,7 +11,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div id="tutorial-wrapper" class="main-content" data-language="{{ lang }}">
|
||||
<div id="tutorial-wrapper" data-game="{{ game }}" data-file="{{ file }}" data-lang="{{ lang }}">
|
||||
<!-- Content generated by JavaScript -->
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
15
WebHostLib/templates/tutorialLanding.html
Normal file
15
WebHostLib/templates/tutorialLanding.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{% extends 'pageWrapper.html' %}
|
||||
|
||||
{% block head %}
|
||||
{% include 'header/grassHeader.html' %}
|
||||
<title>Archipelago Guides</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/tutorialLanding.css") }}" />
|
||||
<script type="application/ecmascript" src="{{ static_autoversion("assets/tutorialLanding.js") }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div id="tutorial-landing" data-game="{{ game }}" data-file="{{ file }}" data-lang="{{ lang }}">
|
||||
<h1 id="page-title">Archipelago Guides</h1>
|
||||
<p id="loading">Loading...</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -33,26 +33,27 @@
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if seed.multidata %}
|
||||
<tr>
|
||||
<td>Players: </td>
|
||||
<td>
|
||||
<ul>
|
||||
{% for team in seed.multidata["names"] %}
|
||||
<li>Team #{{ loop.index }} - {{ team | length }}
|
||||
<ul>
|
||||
{% for player in team %}
|
||||
<li>
|
||||
<a href="{{ url_for("download_raw_patch", seed_id=seed.id, player_id=loop.index) }}">{{ player }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rooms: </td>
|
||||
<tr>
|
||||
<td>Players: </td>
|
||||
<td>
|
||||
<ul>
|
||||
{% for team in seed.multidata["names"] %}
|
||||
{% set outer_loop = loop %}
|
||||
<li>Team #{{ loop.index }} - {{ team | length }}
|
||||
<ul>
|
||||
{% for player in team %}
|
||||
<li>
|
||||
<a href="{{ url_for("download_raw_patch", seed_id=seed.id, player_id=loop.index, team_id=outer_loop.index0) }}">{{ player }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rooms: </td>
|
||||
<td>
|
||||
{% call macros.list_rooms(rooms) %}
|
||||
<li>
|
||||
@@ -69,7 +70,7 @@
|
||||
{% for patch in seed.patches %}
|
||||
|
||||
<li>
|
||||
<a href="{{ url_for("download_raw_patch", seed_id=seed.id, player_id=patch.player) }}">Player {{ patch.player }}</a>
|
||||
<a href="{{ url_for("download_raw_patch", seed_id=seed.id, player_id=patch.player, team_id=0) }}">Player {{ patch.player }}</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@ def uploads():
|
||||
if file.filename.endswith(banned_zip_contents):
|
||||
return "Uploaded data contained a rom file, which is likely to contain copyrighted material. Your file was deleted."
|
||||
elif file.filename.endswith(".apbp"):
|
||||
player = int(file.filename.split("P")[1].split(".")[0].split("_")[0])
|
||||
splitted = file.filename.split("/")[-1][3:].split("P", 1)
|
||||
player = int(splitted[1].split(".")[0].split("_")[0])
|
||||
patches.add(Patch(data=zfile.open(file, "r").read(), player=player))
|
||||
elif file.filename.endswith(".txt"):
|
||||
spoiler = zfile.open(file, "r").read().decode("utf-8-sig")
|
||||
|
||||
Reference in New Issue
Block a user