Compare commits
19 Commits
NewSoupVi-
...
setup_more
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db85a7f554 | ||
|
|
ecadb301c0 | ||
|
|
360ad7197b | ||
|
|
96ae2235d1 | ||
|
|
37b87e3fde | ||
|
|
5b6714d2c0 | ||
|
|
97c07e91d1 | ||
|
|
7cd7111241 | ||
|
|
4b0306102d | ||
|
|
3f139f2efb | ||
|
|
41a62a1a9e | ||
|
|
8837e617e4 | ||
|
|
2bf410f285 | ||
|
|
04fe43d53a | ||
|
|
6bf3067a39 | ||
|
|
8d81513842 | ||
|
|
c27be54a4c | ||
|
|
a6316e9991 | ||
|
|
5130eba886 |
11
.github/workflows/build.yml
vendored
@@ -23,9 +23,10 @@ env:
|
||||
ENEMIZER_VERSION: 7.1
|
||||
# NOTE: since appimage/appimagetool and appimage/type2-runtime does not have tags anymore,
|
||||
# we check the sha256 and require manual intervention if it was updated.
|
||||
APPIMAGETOOL_VERSION: continuous
|
||||
APPIMAGETOOL_X86_64_HASH: '29348a20b80827cd261c28e95172ff828b69d43d4e4e18e3fd069e2c8693c94e'
|
||||
APPIMAGE_RUNTIME_VERSION: continuous
|
||||
APPIMAGE_FORK: 'PopTracker'
|
||||
APPIMAGETOOL_VERSION: 'r-2025-10-19'
|
||||
APPIMAGETOOL_X86_64_HASH: '9493a6b253a01f84acb9c624c38810ecfa11d99daa829b952b0bff43113080f9'
|
||||
APPIMAGE_RUNTIME_VERSION: 'r-2025-08-11'
|
||||
APPIMAGE_RUNTIME_X86_64_HASH: 'e70ffa9b69b211574d0917adc482dd66f25a0083427b5945783965d55b0b0a8b'
|
||||
|
||||
permissions: # permissions required for attestation
|
||||
@@ -141,9 +142,9 @@ jobs:
|
||||
- name: Install build-time dependencies
|
||||
run: |
|
||||
echo "PYTHON=python3.12" >> $GITHUB_ENV
|
||||
wget -nv https://github.com/AppImage/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
|
||||
wget -nv https://github.com/$APPIMAGE_FORK/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
|
||||
echo "$APPIMAGETOOL_X86_64_HASH appimagetool-x86_64.AppImage" | sha256sum -c
|
||||
wget -nv https://github.com/AppImage/type2-runtime/releases/download/$APPIMAGE_RUNTIME_VERSION/runtime-x86_64
|
||||
wget -nv https://github.com/$APPIMAGE_FORK/type2-runtime/releases/download/$APPIMAGE_RUNTIME_VERSION/runtime-x86_64
|
||||
echo "$APPIMAGE_RUNTIME_X86_64_HASH runtime-x86_64" | sha256sum -c
|
||||
chmod a+rx appimagetool-x86_64.AppImage
|
||||
./appimagetool-x86_64.AppImage --appimage-extract
|
||||
|
||||
11
.github/workflows/release.yml
vendored
@@ -11,9 +11,10 @@ env:
|
||||
ENEMIZER_VERSION: 7.1
|
||||
# NOTE: since appimage/appimagetool and appimage/type2-runtime does not have tags anymore,
|
||||
# we check the sha256 and require manual intervention if it was updated.
|
||||
APPIMAGETOOL_VERSION: continuous
|
||||
APPIMAGETOOL_X86_64_HASH: '29348a20b80827cd261c28e95172ff828b69d43d4e4e18e3fd069e2c8693c94e'
|
||||
APPIMAGE_RUNTIME_VERSION: continuous
|
||||
APPIMAGE_FORK: 'PopTracker'
|
||||
APPIMAGETOOL_VERSION: 'r-2025-10-19'
|
||||
APPIMAGETOOL_X86_64_HASH: '9493a6b253a01f84acb9c624c38810ecfa11d99daa829b952b0bff43113080f9'
|
||||
APPIMAGE_RUNTIME_VERSION: 'r-2025-08-11'
|
||||
APPIMAGE_RUNTIME_X86_64_HASH: 'e70ffa9b69b211574d0917adc482dd66f25a0083427b5945783965d55b0b0a8b'
|
||||
|
||||
permissions: # permissions required for attestation
|
||||
@@ -127,9 +128,9 @@ jobs:
|
||||
- name: Install build-time dependencies
|
||||
run: |
|
||||
echo "PYTHON=python3.12" >> $GITHUB_ENV
|
||||
wget -nv https://github.com/AppImage/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
|
||||
wget -nv https://github.com/$APPIMAGE_FORK/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
|
||||
echo "$APPIMAGETOOL_X86_64_HASH appimagetool-x86_64.AppImage" | sha256sum -c
|
||||
wget -nv https://github.com/AppImage/type2-runtime/releases/download/$APPIMAGE_RUNTIME_VERSION/runtime-x86_64
|
||||
wget -nv https://github.com/$APPIMAGE_FORK/type2-runtime/releases/download/$APPIMAGE_RUNTIME_VERSION/runtime-x86_64
|
||||
echo "$APPIMAGE_RUNTIME_X86_64_HASH runtime-x86_64" | sha256sum -c
|
||||
chmod a+rx appimagetool-x86_64.AppImage
|
||||
./appimagetool-x86_64.AppImage --appimage-extract
|
||||
|
||||
2
.github/workflows/unittests.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pytest pytest-subtests pytest-xdist
|
||||
pip install -r ci-requirements.txt
|
||||
python ModuleUpdate.py --yes --force --append "WebHostLib/requirements.txt"
|
||||
python Launcher.py --update_settings # make sure host.yaml exists for tests
|
||||
- name: Unittests
|
||||
|
||||
@@ -189,6 +189,11 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
|
||||
yaml[category][key] = option
|
||||
elif category_name not in yaml:
|
||||
logging.warning(f"Meta: Category {category_name} is not present in {path}.")
|
||||
elif key == "triggers":
|
||||
if "triggers" not in yaml[category_name]:
|
||||
yaml[category_name][key] = []
|
||||
for trigger in option:
|
||||
yaml[category_name][key].append(trigger)
|
||||
else:
|
||||
yaml[category_name][key] = option
|
||||
|
||||
@@ -385,6 +390,8 @@ def roll_meta_option(option_key, game: str, category_dict: dict) -> Any:
|
||||
if options[option_key].supports_weighting:
|
||||
return get_choice(option_key, category_dict)
|
||||
return category_dict[option_key]
|
||||
if option_key == "triggers":
|
||||
return category_dict[option_key]
|
||||
raise Options.OptionError(f"Error generating meta option {option_key} for {game}.")
|
||||
|
||||
|
||||
|
||||
90
WebHostLib/markdown.py
Normal file
@@ -0,0 +1,90 @@
|
||||
import re
|
||||
from collections import Counter
|
||||
|
||||
import mistune
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
|
||||
__all__ = [
|
||||
"ImgUrlRewriteInlineParser",
|
||||
'render_markdown',
|
||||
]
|
||||
|
||||
|
||||
class ImgUrlRewriteInlineParser(mistune.InlineParser):
|
||||
relative_url_base: str
|
||||
|
||||
def __init__(self, relative_url_base: str, hard_wrap: bool = False) -> None:
|
||||
super().__init__(hard_wrap)
|
||||
self.relative_url_base = relative_url_base
|
||||
|
||||
@staticmethod
|
||||
def _find_game_name_by_folder_name(name: str) -> str | None:
|
||||
from worlds.AutoWorld import AutoWorldRegister
|
||||
|
||||
for world_name, world_type in AutoWorldRegister.world_types.items():
|
||||
if world_type.__module__ == f"worlds.{name}":
|
||||
return world_name
|
||||
return None
|
||||
|
||||
def parse_link(self, m: re.Match[str], state: mistune.InlineState) -> int | None:
|
||||
res = super().parse_link(m, state)
|
||||
if res is not None and state.tokens and state.tokens[-1]["type"] == "image":
|
||||
image_token = state.tokens[-1]
|
||||
url: str = image_token["attrs"]["url"]
|
||||
if not url.startswith("/") and not "://" in url:
|
||||
# replace relative URL to another world's doc folder with the webhost folder layout
|
||||
if url.startswith("../../") and "/docs/" in self.relative_url_base:
|
||||
parts = url.split("/", 4)
|
||||
if parts[2] != ".." and parts[3] == "docs":
|
||||
game_name = self._find_game_name_by_folder_name(parts[2])
|
||||
if game_name is not None:
|
||||
url = "/".join(parts[1:2] + [secure_filename(game_name)] + parts[4:])
|
||||
# change relative URL to point to deployment folder
|
||||
url = f"{self.relative_url_base}/{url}"
|
||||
image_token['attrs']['url'] = url
|
||||
return res
|
||||
|
||||
|
||||
def render_markdown(path: str, img_url_base: str | None = None) -> str:
|
||||
markdown = mistune.create_markdown(
|
||||
escape=False,
|
||||
plugins=[
|
||||
"strikethrough",
|
||||
"footnotes",
|
||||
"table",
|
||||
"speedup",
|
||||
],
|
||||
)
|
||||
|
||||
heading_id_count: Counter[str] = Counter()
|
||||
|
||||
def heading_id(text: str) -> str:
|
||||
nonlocal heading_id_count
|
||||
|
||||
# there is no good way to do this without regex
|
||||
s = re.sub(r"[^\w\- ]", "", text.lower()).replace(" ", "-").strip("-")
|
||||
n = heading_id_count[s]
|
||||
heading_id_count[s] += 1
|
||||
if n > 0:
|
||||
s += f"-{n}"
|
||||
return s
|
||||
|
||||
def id_hook(_: mistune.Markdown, state: mistune.BlockState) -> None:
|
||||
for tok in state.tokens:
|
||||
if tok["type"] == "heading" and tok["attrs"]["level"] < 4:
|
||||
text = tok["text"]
|
||||
assert isinstance(text, str)
|
||||
unique_id = heading_id(text)
|
||||
tok["attrs"]["id"] = unique_id
|
||||
tok["text"] = f"<a href=\"#{unique_id}\">{text}</a>" # make header link to itself
|
||||
|
||||
markdown.before_render_hooks.append(id_hook)
|
||||
if img_url_base:
|
||||
markdown.inline = ImgUrlRewriteInlineParser(img_url_base)
|
||||
|
||||
with open(path, encoding="utf-8-sig") as f:
|
||||
document = f.read()
|
||||
html = markdown(document)
|
||||
assert isinstance(html, str), "Unexpected mistune renderer in render_markdown"
|
||||
return html
|
||||
@@ -9,6 +9,7 @@ from werkzeug.utils import secure_filename
|
||||
|
||||
from worlds.AutoWorld import AutoWorldRegister, World
|
||||
from . import app, cache
|
||||
from .markdown import render_markdown
|
||||
from .models import Seed, Room, Command, UUID, uuid4
|
||||
from Utils import title_sorted
|
||||
|
||||
@@ -27,49 +28,6 @@ def get_visible_worlds() -> dict[str, type(World)]:
|
||||
return worlds
|
||||
|
||||
|
||||
def render_markdown(path: str) -> str:
|
||||
import mistune
|
||||
from collections import Counter
|
||||
|
||||
markdown = mistune.create_markdown(
|
||||
escape=False,
|
||||
plugins=[
|
||||
"strikethrough",
|
||||
"footnotes",
|
||||
"table",
|
||||
"speedup",
|
||||
],
|
||||
)
|
||||
|
||||
heading_id_count: Counter[str] = Counter()
|
||||
|
||||
def heading_id(text: str) -> str:
|
||||
nonlocal heading_id_count
|
||||
import re # there is no good way to do this without regex
|
||||
|
||||
s = re.sub(r"[^\w\- ]", "", text.lower()).replace(" ", "-").strip("-")
|
||||
n = heading_id_count[s]
|
||||
heading_id_count[s] += 1
|
||||
if n > 0:
|
||||
s += f"-{n}"
|
||||
return s
|
||||
|
||||
def id_hook(_: mistune.Markdown, state: mistune.BlockState) -> None:
|
||||
for tok in state.tokens:
|
||||
if tok["type"] == "heading" and tok["attrs"]["level"] < 4:
|
||||
text = tok["text"]
|
||||
assert isinstance(text, str)
|
||||
unique_id = heading_id(text)
|
||||
tok["attrs"]["id"] = unique_id
|
||||
tok["text"] = f"<a href=\"#{unique_id}\">{text}</a>" # make header link to itself
|
||||
|
||||
markdown.before_render_hooks.append(id_hook)
|
||||
|
||||
with open(path, encoding="utf-8-sig") as f:
|
||||
document = f.read()
|
||||
return markdown(document)
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
@app.errorhandler(jinja2.exceptions.TemplateNotFound)
|
||||
def page_not_found(err):
|
||||
@@ -91,10 +49,9 @@ def game_info(game, lang):
|
||||
theme = get_world_theme(game)
|
||||
secure_game_name = secure_filename(game)
|
||||
lang = secure_filename(lang)
|
||||
document = render_markdown(os.path.join(
|
||||
app.static_folder, "generated", "docs",
|
||||
secure_game_name, f"{lang}_{secure_game_name}.md"
|
||||
))
|
||||
file_dir = os.path.join(app.static_folder, "generated", "docs", secure_game_name)
|
||||
file_dir_url = url_for("static", filename=f"generated/docs/{secure_game_name}")
|
||||
document = render_markdown(os.path.join(file_dir, f"{lang}_{secure_game_name}.md"), file_dir_url)
|
||||
return render_template(
|
||||
"markdown_document.html",
|
||||
title=f"{game} Guide",
|
||||
@@ -119,10 +76,9 @@ def tutorial(game: str, file: str):
|
||||
theme = get_world_theme(game)
|
||||
secure_game_name = secure_filename(game)
|
||||
file = secure_filename(file)
|
||||
document = render_markdown(os.path.join(
|
||||
app.static_folder, "generated", "docs",
|
||||
secure_game_name, file+".md"
|
||||
))
|
||||
file_dir = os.path.join(app.static_folder, "generated", "docs", secure_game_name)
|
||||
file_dir_url = url_for("static", filename=f"generated/docs/{secure_game_name}")
|
||||
document = render_markdown(os.path.join(file_dir, f"{file}.md"), file_dir_url)
|
||||
return render_template(
|
||||
"markdown_document.html",
|
||||
title=f"{game} Guide",
|
||||
|
||||
@@ -4,8 +4,7 @@ pony>=0.7.19; python_version <= '3.12'
|
||||
pony @ git+https://github.com/black-sliver/pony@7feb1221953b7fa4a6735466bf21a8b4d35e33ba#0.7.19; python_version >= '3.13'
|
||||
waitress>=3.0.2
|
||||
Flask-Caching>=2.3.0
|
||||
Flask-Compress>=1.17; python_version >= '3.12'
|
||||
Flask-Compress==1.18; python_version <= '3.11' # 3.11's pkg_resources can't resolve the new "backports.zstd" dependency
|
||||
Flask-Compress==1.18 # pkg_resources can't resolve the "backports.zstd" dependency of >1.18, breaking ModuleUpdate.py
|
||||
Flask-Limiter>=3.12
|
||||
bokeh>=3.6.3
|
||||
markupsafe>=3.0.2
|
||||
|
||||
3
ci-requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
pytest>=8.4.2,<9 # pytest 9.0.0 is broken for our CI
|
||||
pytest-xdist>=3.8.0
|
||||
pytest-subtests>=0.15.0 # will not be required anymore once we upgrade to pytest 9.x
|
||||
@@ -8,3 +8,7 @@ SELFLAUNCH: false
|
||||
# Host Address. This is the address encoded into the patch that will be used for client auto-connect.
|
||||
# Set as your local IP (192.168.x.x) to serve over LAN.
|
||||
HOST_ADDRESS: localhost
|
||||
|
||||
# Asset redistribution rights. If true, the host affirms they have been given explicit permission to redistribute
|
||||
# the proprietary assets in WebHostLib
|
||||
#ASSET_RIGHTS: false
|
||||
|
||||
@@ -647,6 +647,16 @@ class Version(NamedTuple):
|
||||
build: int
|
||||
```
|
||||
|
||||
If constructing version information as a dict for a custom client rather than as a NamedTuple built into the CommonClient, you must add the `class` key to allow Archipelago to compare version support.
|
||||
```
|
||||
"version": {
|
||||
"class": "Version",
|
||||
"build": X,
|
||||
"major": Y,
|
||||
"minor": Z
|
||||
}
|
||||
```
|
||||
|
||||
### SlotType
|
||||
An enum representing the nature of a slot.
|
||||
|
||||
|
||||
11
kvui.py
@@ -34,6 +34,17 @@ from kivy.config import Config
|
||||
Config.set("input", "mouse", "mouse,disable_multitouch")
|
||||
Config.set("kivy", "exit_on_escape", "0")
|
||||
Config.set("graphics", "multisamples", "0") # multisamples crash old intel drivers
|
||||
|
||||
# Workaround for an issue where importing kivy.core.window before loading sounds
|
||||
# will hang the whole application on Linux once the first sound is loaded.
|
||||
# kivymd imports kivy.core.window, so we have to do this before the first kivymd import.
|
||||
# No longer necessary when we switch to kivy 3.0.0, which fixes this issue.
|
||||
from kivy.core.audio import SoundLoader
|
||||
for classobj in SoundLoader._classes:
|
||||
# The least invasive way to force a SoundLoader class to load its audio engine seems to be calling
|
||||
# .extensions(), which e.g. in audio_sdl2.pyx then calls a function called "mix_init()"
|
||||
classobj.extensions()
|
||||
|
||||
from kivymd.uix.divider import MDDivider
|
||||
from kivy.core.window import Window
|
||||
from kivy.core.clipboard import Clipboard
|
||||
|
||||
17
setup.py
@@ -63,18 +63,11 @@ from Cython.Build import cythonize
|
||||
|
||||
|
||||
non_apworlds: set[str] = {
|
||||
"A Link to the Past",
|
||||
"Adventure",
|
||||
"Archipelago",
|
||||
"Lufia II Ancient Cave",
|
||||
"Meritous",
|
||||
"Ocarina of Time",
|
||||
"Overcooked! 2",
|
||||
"Raft",
|
||||
"Sudoku",
|
||||
"Super Mario 64",
|
||||
"VVVVVV",
|
||||
"Wargroove",
|
||||
"Archipelago", # needs a way to specify load order
|
||||
"Final Fantasy", # loads json files badly
|
||||
"Lufia II Ancient Cave", # loads basepatch badly
|
||||
"Ocarina of Time", # has executables in folder
|
||||
"Raft", # loads json files badly
|
||||
}
|
||||
|
||||
|
||||
|
||||
78
test/webhost/test_markdown.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import os
|
||||
import unittest
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from mistune import HTMLRenderer, Markdown
|
||||
|
||||
from WebHostLib.markdown import ImgUrlRewriteInlineParser, render_markdown
|
||||
|
||||
|
||||
class ImgUrlRewriteTest(unittest.TestCase):
|
||||
markdown: Markdown
|
||||
base_url = "/static/generated/docs/some_game"
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.markdown = Markdown(
|
||||
renderer=HTMLRenderer(escape=False),
|
||||
inline=ImgUrlRewriteInlineParser(self.base_url),
|
||||
)
|
||||
|
||||
def test_relative_img_rewrite(self) -> None:
|
||||
html = self.markdown("")
|
||||
self.assertIn(f'src="{self.base_url}/image.png"', html)
|
||||
|
||||
def test_absolute_img_no_rewrite(self) -> None:
|
||||
html = self.markdown("")
|
||||
self.assertIn(f'src="/image.png"', html)
|
||||
self.assertNotIn(self.base_url, html)
|
||||
|
||||
def test_remote_img_no_rewrite(self) -> None:
|
||||
html = self.markdown("")
|
||||
self.assertIn(f'src="https://example.com/image.png"', html)
|
||||
self.assertNotIn(self.base_url, html)
|
||||
|
||||
def test_relative_link_no_rewrite(self) -> None:
|
||||
# The parser is only supposed to update images, not links.
|
||||
html = self.markdown("[Link](image.png)")
|
||||
self.assertIn(f'href="image.png"', html)
|
||||
self.assertNotIn(self.base_url, html)
|
||||
|
||||
def test_absolute_link_no_rewrite(self) -> None:
|
||||
html = self.markdown("[Link](/image.png)")
|
||||
self.assertIn(f'href="/image.png"', html)
|
||||
self.assertNotIn(self.base_url, html)
|
||||
|
||||
def test_auto_link_no_rewrite(self) -> None:
|
||||
html = self.markdown("<https://example.com/image.png>")
|
||||
self.assertIn(f'href="https://example.com/image.png"', html)
|
||||
self.assertNotIn(self.base_url, html)
|
||||
|
||||
def test_relative_img_to_other_game(self) -> None:
|
||||
html = self.markdown("")
|
||||
self.assertIn(f'src="{self.base_url}/../Archipelago/image.png"', html)
|
||||
|
||||
|
||||
class RenderMarkdownTest(unittest.TestCase):
|
||||
"""Tests that render_markdown does the right thing."""
|
||||
base_url = "/static/generated/docs/some_game"
|
||||
|
||||
def test_relative_img_rewrite(self) -> None:
|
||||
f = NamedTemporaryFile(delete=False)
|
||||
try:
|
||||
f.write("".encode("utf-8"))
|
||||
f.close()
|
||||
html = render_markdown(f.name, self.base_url)
|
||||
self.assertIn(f'src="{self.base_url}/image.png"', html)
|
||||
finally:
|
||||
os.unlink(f.name)
|
||||
|
||||
def test_no_img_rewrite(self) -> None:
|
||||
f = NamedTemporaryFile(delete=False)
|
||||
try:
|
||||
f.write("".encode("utf-8"))
|
||||
f.close()
|
||||
html = render_markdown(f.name)
|
||||
self.assertIn(f'src="image.png"', html)
|
||||
self.assertNotIn(self.base_url, html)
|
||||
finally:
|
||||
os.unlink(f.name)
|
||||
@@ -88,9 +88,8 @@ You only have to do these steps once.
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
@@ -88,9 +88,8 @@ Sólo hay que seguir estos pasos una vez.
|
||||
1. Comienza en la pantalla del menú principal de RetroArch.
|
||||
2. Ve a Ajustes --> Interfaz de usario. Configura "Mostrar ajustes avanzados" en ON.
|
||||
3. Ve a Ajustes --> Red. Pon "Comandos de red" en ON. (Se encuentra bajo Request Device 16.) Deja en 55355 el valor por defecto,
|
||||
el Puerto de comandos de red.
|
||||
|
||||

|
||||
el Puerto de comandos de red. \
|
||||

|
||||
4. Ve a Menú principal --> Actualizador en línea --> Descargador de núcleos. Desplázate y selecciona "Nintendo - SNES /
|
||||
SFC (bsnes-mercury Performance)".
|
||||
|
||||
|
||||
@@ -89,9 +89,8 @@ Vous n'avez qu'à faire ces étapes qu'une fois.
|
||||
1. Entrez dans le menu principal RetroArch
|
||||
2. Allez dans Réglages --> Interface utilisateur. Mettez "Afficher les réglages avancés" sur ON.
|
||||
3. Allez dans Réglages --> Réseau. Mettez "Commandes Réseau" sur ON. (trouvé sous Request Device 16.) Laissez le
|
||||
Port des commandes réseau à 555355.
|
||||
|
||||

|
||||
Port des commandes réseau à 555355. \
|
||||

|
||||
4. Allez dans Menu Principal --> Mise à jour en ligne --> Téléchargement de cœurs. Descendez jusqu'a"Nintendo - SNES / SFC (bsnes-mercury Performance)" et
|
||||
sélectionnez le.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 20 KiB |
@@ -13,7 +13,7 @@ All scraps or any collectable item on the ground (except from Loot Crates) and i
|
||||
Beating the evil train from Hell named "Charles".
|
||||
|
||||
## How is the game managed in Nightmare mode?
|
||||
At death, the player has to restart a brand-new game, giving him the choice to stay under the Nightmare mode or continuing with the Normal mode if considered too hard.
|
||||
At death, the player has to restart a brand-new game, giving them the choice to stay under the Nightmare Mode or continuing with the Classic Mode if considered too hard.
|
||||
In this case, all collected items will be redistributed in the inventory and the missions states will be kept.
|
||||
The Deathlink is not implemented yet. When this option will be available, a choice will be provided to:
|
||||
* Disable the Deathlink
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
## Où est la page d'options ?
|
||||
La [page d'options du joueur pour ce jeu](../player-options) contient toutes les options pour configurer et exporter un fichier de configuration yaml.
|
||||
|
||||
## Qu'est ce que la randomisation fait au jeu ?
|
||||
Tous les débrits ou n'importe quel objet ramassable au sol (excepté les Caisses à Butin) et objets reçus par les missions de PNJs sont considérés comme emplacements à vérifier.
|
||||
## Qu'est-ce que la randomisation fait au jeu ?
|
||||
Tous les débris ou n'importe quel objet ramassable au sol (excepté les Caisses à Butin) et objets reçus par les missions de PNJs sont considérés comme emplacements à vérifier.
|
||||
|
||||
## Quel est le but de Choo-Choo Charles lorsqu'il est randomisé ?
|
||||
Vaincre le train démoniaque de l'Enfer nommé "Charles".
|
||||
|
||||
## Comment le jeu est-il géré en mode Nightmare ?
|
||||
À sa mort, le joueur doit relancer une toute nouvelle partie, lui donnant la possisilité de rester en mode Nightmare ou de poursuivre la partie en mode Normal s'il considère la partie trop difficile.
|
||||
## Comment le jeu est-il géré en Mode Cauchemar ?
|
||||
À sa mort, le joueur doit relancer une toute nouvelle partie, lui donnant la possibilité de rester en Mode Cauchemar ou de poursuivre la partie en Mode Classique s'il considère la partie trop difficile.
|
||||
Dans ce cas, tous les objets collectés seront redistribués dans l'inventaire et les états des missions seront conservés.
|
||||
Le Deathlink n'est pas implémenté pour l'instant. Lorsque cette option sera disponible, un choix sera fourni pour :
|
||||
* Désactiver le Deathlink
|
||||
@@ -18,7 +18,7 @@ Le Deathlink n'est pas implémenté pour l'instant. Lorsque cette option sera di
|
||||
* Activer le Deathlink strict avec suppression de la sauvegarde lorsqu'un évènement Deathlink est reçu
|
||||
|
||||
## À quoi ressemble un objet d'un autre monde dans Choo-Choo Charles ?
|
||||
Les apparances des objets sont conservés.
|
||||
Les apparences des objets sont conservées.
|
||||
Tout indice qui ne peut pas être représenté normalement dans le jeu est remplacé par l'Easter Egg "DeadDuck" miniaturisé qui peut être vu en dehors des limites murales physiques du jeu original.
|
||||
|
||||
## Comment le joueur est-il informé par une transmission d'objet et des indices ?
|
||||
@@ -29,7 +29,7 @@ La même méthode est utilisée pour les indices.
|
||||
Non, ceci est un travail en cours.
|
||||
Les options suivantes seront possibles une fois les implémentations disponibles :
|
||||
|
||||
À n'importe quel moment, le joueur peu appuyer sur l'une des touches suivantes pour afficher la console dans le jeu :
|
||||
À n'importe quel moment, le joueur peut appuyer sur l'une des touches suivantes pour afficher la console dans le jeu :
|
||||
* "~" (qwerty)
|
||||
* "²" (azerty)
|
||||
* "F10"
|
||||
|
||||
@@ -27,7 +27,7 @@ The [Player Options page](/games/Choo-Choo%20Charles/player-options) allows to c
|
||||
Before playing, it is highly recommended to check out the **[Known Issues](setup_en#known-issues)** section
|
||||
* The game console must be opened to type Archipelago commands, press "F10" key or "`" (or "~") key in querty ("²" key in azerty)
|
||||
* Type ``/connect <IP> <PlayerName>`` with \<IP\> and \<PlayerName\> found on the hosting Archipelago web page in the form ``archipelago.gg:XXXXX`` and ``CCCharles``
|
||||
* Disconnection is automatic at game closure but can be manually done with ``/disconnect``
|
||||
* Disconnection is automatic at game closure, but can be manually done with ``/disconnect``
|
||||
|
||||
## Hosting a MultiWorld or Single-Player Game
|
||||
See the [Mod Download](setup_en#mod-download) section to get the **cccharles.apworld** file.
|
||||
|
||||
@@ -4,7 +4,7 @@ Cette page est un guide simplifié de la [page du Mod Randomiseur Multiworld de
|
||||
## Exigences et Logiciels Nécessaires
|
||||
* Un ordinateur utilisant Windows (le Mod n'est pas utilisable sous Linux ou Mac)
|
||||
* [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases)
|
||||
* Une copie légale du jeu original Choo-Choo Charles (peut être trouvé sur [Steam](https://store.steampowered.com/app/1766740/ChooChoo_Charles/)
|
||||
* Une copie légale du jeu original Choo-Choo Charles (peut être trouvé sur [Steam](https://store.steampowered.com/app/1766740/ChooChoo_Charles/))
|
||||
|
||||
## Installation du Mod pour jouer
|
||||
### Téléchargement du Mod
|
||||
@@ -27,7 +27,7 @@ La [page d'Options Joueur](/games/Choo-Choo%20Charles/player-options) permet de
|
||||
Avant de jouer, il est fortement recommandé de consulter la section **[Problèmes Connus](setup_fr#probl%C3%A8mes-connus)**.
|
||||
* La console du jeu doit être ouverte pour taper des commandes Archipelago, appuyer sur la touche "F10" ou "`" (ou "~") en querty (touche "²" en azerty)
|
||||
* Taper ``/connect <IP> <NomDuJoueur>`` avec \<IP\> et \<NomDuJoueur\> trouvés sur la page web d'hébergement Archipelago sous la forme ``archipelago.gg:XXXXX`` et ``CCCharles``
|
||||
* La déconnexion est automatique à la fermeture du jeu mais peut être faite manuellement avec ``/disconnect``
|
||||
* La déconnexion est automatique à la fermeture du jeu, mais peut être faite manuellement avec ``/disconnect``
|
||||
|
||||
## Héberger une partie MultiWorld ou un Seul Joueur
|
||||
Voir la section [Téléchargement du Mod](setup_fr#téléchargement-du-mod) pour récupérer le fichier **cccharles.apworld**.
|
||||
@@ -39,7 +39,7 @@ Suivre ces étapes pour héberger une session multijoueur à distance ou locale
|
||||
2. Placer le **CCCharles.yaml** dans **Archipelago/Players/** avec le YAML de chaque joueur à héberger
|
||||
3. Exécuter le lanceur Archipelago et cliquer sur "Generate" pour configurer une partie avec les YAML dans **Archipelago/output/**
|
||||
4. Pour une session multijoueur, aller à la [page Archipelago HOST GAME](https://archipelago.gg/uploads)
|
||||
5. Cliquer sur "Upload File" et selectionner le **AP_\<seed\>.zip** généré dans **Archipelago/output/**
|
||||
5. Cliquer sur "Upload File" et sélectionner le **AP_\<seed\>.zip** généré dans **Archipelago/output/**
|
||||
6. Envoyer la page de la partie générée à chaque joueur
|
||||
|
||||
Pour une session locale à un seul joueur, cliquer sur "Host" dans le lanceur Archipelago en utilisant **AP_\<seed\>.zip** généré dans **Archipelago/output/**
|
||||
|
||||
@@ -609,8 +609,8 @@ class CV64PatchExtensions(APPatchExtension):
|
||||
|
||||
# Shimmy speed increase hack
|
||||
if options["increase_shimmy_speed"]:
|
||||
rom_data.write_int32(0x97EB4, 0x803FE9F0)
|
||||
rom_data.write_int32s(0xBFE9F0, patches.shimmy_speed_modifier)
|
||||
rom_data.write_int32(0x97EB4, 0x803FEA20)
|
||||
rom_data.write_int32s(0xBFEA20, patches.shimmy_speed_modifier)
|
||||
|
||||
# Disable landing fall damage
|
||||
if options["fall_guard"]:
|
||||
|
||||
@@ -110,7 +110,7 @@ def get_item_counts(world: "CVCotMWorld") -> Dict[ItemClassification, Dict[str,
|
||||
|
||||
# If Halve DSS Cards Placed is on, determine which cards we will exclude here.
|
||||
if world.options.halve_dss_cards_placed:
|
||||
excluded_cards = list(ACTION_CARDS.union(ATTRIBUTE_CARDS))
|
||||
excluded_cards = sorted(ACTION_CARDS.union(ATTRIBUTE_CARDS))
|
||||
|
||||
has_freeze_action = False
|
||||
has_freeze_attr = False
|
||||
|
||||
@@ -111,9 +111,8 @@ You only have to do these steps once. Note, RetroArch 1.9.x will not work as it
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 627 KiB After Width: | Height: | Size: 493 KiB |
@@ -92,7 +92,7 @@ appropriate to your operating system, and extract the folder to a convenient loc
|
||||
Archipelago is to place the extracted game folder into the `Archipelago` directory and rename it to just be "Factorio".
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
Next, you should launch your Factorio Server by running `factorio.exe`, which is located at: `bin/x64/factorio.exe`. You
|
||||
will be asked to log in to your Factorio account using the same credentials you used on Factorio's website. After you
|
||||
@@ -122,7 +122,7 @@ This allows you to host your own Factorio game.
|
||||
Archipelago if you chose to include it during the installation process.
|
||||
6. Enter `/connect [server-address]` into the input box at the bottom of the Archipelago Client and press "Enter"
|
||||
|
||||

|
||||

|
||||
|
||||
7. Launch your Factorio Client
|
||||
8. Click on "Multiplayer" in the main menu
|
||||
|
||||
@@ -115,9 +115,8 @@ You only have to do these steps once. Note, RetroArch 1.9.x will not work as it
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
@@ -123,10 +123,8 @@ Vous ne devez faire ces étapes qu'une fois. À noter que RetroArch 1.9.x ne fon
|
||||
1. Entrez dans le menu principal de RetroArch.
|
||||
2. Allez dans Settings --> User Interface. Activez l'option "Show Advanced Settings".
|
||||
3. Allez dans Settings --> Network. Activez l'option "Network Commands", qui se trouve sous "Request Device 16".
|
||||
Laissez le "Network Command Port" à sa valeur par defaut, qui devrait être 55355.
|
||||
|
||||
|
||||

|
||||
Laissez le "Network Command Port" à sa valeur par defaut, qui devrait être 55355. \
|
||||

|
||||
4. Allez dans le Menu Principal --> Online Updater --> Core Downloader. Trouvez et sélectionnez "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
BIN
worlds/generic/docs/retroarch-network-commands-en.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
worlds/generic/docs/retroarch-network-commands-fr.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -73,9 +73,8 @@ You only have to do these steps once. Note, RetroArch 1.9.x will not work as it
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - Gameboy / Color (SameBoy)".
|
||||
|
||||
#### BizHawk 2.8 or newer (older versions untested)
|
||||
|
||||
@@ -48,7 +48,7 @@ A window will open with a few settings to enter:
|
||||
- **Slot name**: Put the player name you specified in your YAML config file in this field.
|
||||
- **Password**: If the server has a password, put it there.
|
||||
|
||||

|
||||

|
||||
|
||||
Once all those fields were filled appropriately, click on the `Connect to Archipelago` button below to try connecting to
|
||||
the Archipelago server.
|
||||
@@ -67,7 +67,7 @@ You should see a window with settings to fill:
|
||||
- **Output ROM directory**: This is where the randomized ROMs will be put. No need to change this unless you want them
|
||||
to be created in a very specific folder.
|
||||
|
||||

|
||||

|
||||
|
||||
There also a few cosmetic options you can fill before clicking the `Build ROM` button which should create your
|
||||
randomized seed if everything went right.
|
||||
@@ -83,7 +83,7 @@ the items you have received from other players.
|
||||
|
||||
You should see the following window:
|
||||
|
||||

|
||||

|
||||
|
||||
As written, you have to open the newly generated ROM inside either Retroarch or Bizhawk using the Genesis Plus GX core.
|
||||
Be careful to select that core, because any other core (e.g. BlastEm) won't work.
|
||||
@@ -116,6 +116,6 @@ The client is packaged with both an **automatic item tracker** and an **automati
|
||||
If you don't know all checks in the game, don't be afraid: you can click the `Where is it?` button that will show
|
||||
you a screenshot of where the location actually is.
|
||||
|
||||

|
||||

|
||||
|
||||
Have fun!
|
||||
Have fun!
|
||||
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 986 B |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -106,9 +106,8 @@ You only have to do these steps once. Note, RetroArch 1.9.x will not work as it
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ Wenn du einer Multiworld beitrittst, wirst du gefordert eine YAML-Datei bei dem
|
||||
erhälst du (in der Regel) einen Link vom Host der Multiworld. Dieser führt dich zu einem Raum, in dem alle
|
||||
teilnehmenden Spieler (bzw. Welten) aufgelistet sind. Du solltest dich dann auf **deine** Welt konzentrieren
|
||||
und klicke dann auf `Download APZ5 File...`.
|
||||

|
||||

|
||||
|
||||
Führe die `.apz5`-Datei mit einem Doppelklick aus, um deinen Ocarina Of Time-Client zu starten, sowie das patchen
|
||||
deiner ROM. Ist dieser Prozess fertig (kann etwas dauern), startet sich der Client und der Emulator automatisch
|
||||
|
||||
@@ -34,6 +34,7 @@ code contributors also reported bugs and participated in beta testing.
|
||||
* 7thAce (@7thAce) - Pulsar
|
||||
* Panicmoon (@panicmoon.bsky.social) - Skylord
|
||||
* JayborinoPlays (@Jayborino) - Oppressor
|
||||
* MindHawk (@MindHawk) - Caladrius
|
||||
|
||||
## Maintenance of 2024 release
|
||||
* Ziktofel (@Ziktofel)
|
||||
|
||||
@@ -124,9 +124,8 @@ You only have to do these steps once. Note, RetroArch 1.9.x will not work as it
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
@@ -100,9 +100,8 @@ You only have to do these steps once. Note, RetroArch 1.9.x will not work as it
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
@@ -120,9 +120,8 @@ You only have to do these steps once. Note, RetroArch 1.9.x will not work as it
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
@@ -108,8 +108,8 @@ You only have to do these steps once.
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ RetroArch 1.9.x will not work, as it is older than 1.10.3.
|
||||
- "Sega - MS/GG/MD/CD (Genesis Plus GX)
|
||||
3. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
4. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
Network Command Port at 55355. \
|
||||

|
||||
|
||||
### Linux Setup
|
||||
|
||||
|
||||