Update WebHost to include new tutorial landing page.
- Added MSU-1 setup guide - Updated header and landing page for title change - Re-structured tutorial files - Added tutorials.json, which is used when constructing the new /tutorial page
This commit is contained in:
parent
eb58ee2422
commit
b063407d2b
|
@ -79,10 +79,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')
|
||||
|
|
|
@ -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>`;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
[
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,68 @@
|
|||
# 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 copyrighted music, your VOD may be muted. In the worst scenario, you may receive a DMCA
|
||||
take-down notice. Please be careful to only stream music for which you have the rights to do so.
|
|
@ -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();
|
||||
});
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
<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,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>
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
Loading…
Reference in New Issue