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:
Fabian Dill
2021-01-17 06:50:25 +01:00
35 changed files with 965 additions and 187 deletions

View File

@@ -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')

View File

@@ -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"

View File

@@ -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>`;
});
});

View 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"
]
}
]
}
]
}
]

View 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)

View 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)

View 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.

View 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
```
![Uncle Example](https://cdn.discordapp.com/attachments/731214280439103580/794953870903083058/unknown.png)
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.

View 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();
});

View File

@@ -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
}
}

View File

@@ -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;

View 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;
}

View File

@@ -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>

View File

@@ -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">

View File

@@ -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">

View File

@@ -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>

View File

@@ -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) }}">

View File

@@ -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 %}

View 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 %}

View File

@@ -33,26 +33,27 @@
</tr>
{% endif %}
{% if seed.multidata %}
<tr>
<td>Players:&nbsp;</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:&nbsp;</td>
<tr>
<td>Players:&nbsp;</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:&nbsp;</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>

View File

@@ -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")