mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-04-07 19:38:12 -07:00
Merge branch 'main' of https://github.com/Berserker66/MultiWorld-Utilities into triforce_changes
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
import multiprocessing
|
||||
from datetime import timedelta, datetime
|
||||
import concurrent.futures
|
||||
import sys
|
||||
import typing
|
||||
import time
|
||||
@@ -136,6 +137,7 @@ def autohost(config: dict):
|
||||
|
||||
multiworlds = {}
|
||||
|
||||
guardians = concurrent.futures.ThreadPoolExecutor(2, thread_name_prefix="Guardian")
|
||||
|
||||
class MultiworldInstance():
|
||||
def __init__(self, room: Room, config: dict):
|
||||
@@ -153,12 +155,18 @@ class MultiworldInstance():
|
||||
args=(self.room_id, self.ponyconfig),
|
||||
name="MultiHost")
|
||||
self.process.start()
|
||||
self.guardian = guardians.submit(self._collect)
|
||||
|
||||
def stop(self):
|
||||
if self.process:
|
||||
self.process.terminate()
|
||||
self.process = None
|
||||
|
||||
def _collect(self):
|
||||
self.process.join() # wait for process to finish
|
||||
self.process = None
|
||||
self.guardian = None
|
||||
|
||||
|
||||
from .models import Room, Generation, STATE_QUEUED, STATE_STARTED, STATE_ERROR, db, Seed
|
||||
from .customserver import run_server_process
|
||||
|
||||
@@ -55,7 +55,7 @@ window.addEventListener('load', () => {
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
adjustTableHeight();
|
||||
tables.draw()
|
||||
tables.draw();
|
||||
});
|
||||
|
||||
$(".table-wrapper").scrollsync({
|
||||
|
||||
@@ -126,10 +126,8 @@ done so already, please do this now. SD2SNES and FXPak Pro users may download th
|
||||
[on this page](http://usb2snes.com/#supported-platforms).
|
||||
|
||||
1. Close your emulator, which may have auto-launched.
|
||||
2. Close QUsb2Snes, which launched automatically with the client.
|
||||
3. Launch the appropriate version of QUsb2Snes (v0.7.16).
|
||||
4. Power on your device and load the ROM.
|
||||
5. Observe the client window now shows "SNES Device: Connected", and lists the name of your device.
|
||||
2. Power on your device and load the ROM.
|
||||
3. Observe the client window now shows "SNES Device: Connected", and lists the name of your device.
|
||||
|
||||
### Connect to the MultiServer
|
||||
The patch file which launched your client should have automatically connected you to the MultiServer.
|
||||
|
||||
@@ -2,9 +2,17 @@ let spriteData = null;
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const gameSettings = document.getElementById('weighted-settings');
|
||||
Promise.all([fetchPlayerSettingsYaml(), fetchPlayerSettingsJson(), fetchSpriteData()]).then((results) => {
|
||||
Promise.all([fetchWeightedSettingsYaml(), fetchWeightedSettingsJson(), fetchSpriteData()]).then((results) => {
|
||||
// Load YAML into object
|
||||
const sourceData = jsyaml.safeLoad(results[0], { json: true });
|
||||
const wsVersion = sourceData.ws_version;
|
||||
delete sourceData.ws_version; // Do not include the settings version number in the export
|
||||
|
||||
// Check if settings exist in localStorage. If no settings are present, this is a first load (or reset to default)
|
||||
// and the version number should be silently updated
|
||||
if (!localStorage.getItem('weightedSettings1')) {
|
||||
localStorage.setItem('wsVersion', wsVersion);
|
||||
}
|
||||
|
||||
// Update localStorage with three settings objects. Preserve original objects if present.
|
||||
for (let i=1; i<=3; i++) {
|
||||
@@ -25,6 +33,16 @@ window.addEventListener('load', () => {
|
||||
document.getElementById('export-button').addEventListener('click', exportSettings);
|
||||
document.getElementById('reset-to-default').addEventListener('click', resetToDefaults);
|
||||
adjustHeaderWidth();
|
||||
|
||||
if (localStorage.getItem('wsVersion') !== wsVersion) {
|
||||
const userWarning = document.getElementById('user-warning');
|
||||
const messageSpan = document.createElement('span');
|
||||
messageSpan.innerHTML = "A new version of the weighted settings file is available. Click here to update!" +
|
||||
"<br />Be aware this will also reset your presets, so you should export them now if you want to save them.";
|
||||
userWarning.appendChild(messageSpan);
|
||||
userWarning.style.display = 'block';
|
||||
userWarning.addEventListener('click', resetToDefaults);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
gameSettings.innerHTML = `
|
||||
@@ -37,7 +55,7 @@ window.addEventListener('load', () => {
|
||||
document.getElementById('generate-race').addEventListener('click', () => generateGame(true));
|
||||
});
|
||||
|
||||
const fetchPlayerSettingsYaml = () => new Promise((resolve, reject) => {
|
||||
const fetchWeightedSettingsYaml = () => new Promise((resolve, reject) => {
|
||||
const ajax = new XMLHttpRequest();
|
||||
ajax.onreadystatechange = () => {
|
||||
if (ajax.readyState !== 4) { return; }
|
||||
@@ -51,7 +69,7 @@ const fetchPlayerSettingsYaml = () => new Promise((resolve, reject) => {
|
||||
ajax.send();
|
||||
});
|
||||
|
||||
const fetchPlayerSettingsJson = () => new Promise((resolve, reject) => {
|
||||
const fetchWeightedSettingsJson = () => new Promise((resolve, reject) => {
|
||||
const ajax = new XMLHttpRequest();
|
||||
ajax.onreadystatechange = () => {
|
||||
if (ajax.readyState !== 4) { return; }
|
||||
@@ -113,6 +131,7 @@ const handleOptionChange = (event) => {
|
||||
};
|
||||
|
||||
const populateSettings = () => {
|
||||
buildSpriteOptions();
|
||||
const presetNumber = document.getElementById('preset-number').value;
|
||||
const settings = JSON.parse(localStorage.getItem(`weightedSettings${presetNumber}`))
|
||||
const settingsInputs = Array.from(document.querySelectorAll('.setting'));
|
||||
@@ -206,7 +225,21 @@ const buildUI = (settings, spriteData) => {
|
||||
settingsWrapper.appendChild(spriteOptionsHeader);
|
||||
|
||||
const spriteOptionsWrapper = document.createElement('div');
|
||||
spriteOptionsWrapper.setAttribute('id', 'sprite-options-wrapper');
|
||||
spriteOptionsWrapper.className = 'setting-wrapper';
|
||||
settingsWrapper.appendChild(spriteOptionsWrapper);
|
||||
|
||||
// Append sprite picker
|
||||
settingsWrapper.appendChild(buildSpritePicker(spriteData));
|
||||
};
|
||||
|
||||
const buildSpriteOptions = () => {
|
||||
const spriteOptionsWrapper = document.getElementById('sprite-options-wrapper');
|
||||
|
||||
// Clear the contents of the wrapper div
|
||||
while(spriteOptionsWrapper.firstChild){
|
||||
spriteOptionsWrapper.removeChild(spriteOptionsWrapper.lastChild);
|
||||
}
|
||||
|
||||
const spriteOptionsTitle = document.createElement('span');
|
||||
spriteOptionsTitle.className = 'title-span';
|
||||
@@ -240,11 +273,6 @@ const buildUI = (settings, spriteData) => {
|
||||
|
||||
spriteOptionsTable.appendChild(tbody);
|
||||
spriteOptionsWrapper.appendChild(spriteOptionsTable);
|
||||
|
||||
settingsWrapper.appendChild(spriteOptionsWrapper);
|
||||
|
||||
// Append sprite picker
|
||||
settingsWrapper.appendChild(buildSpritePicker(spriteData));
|
||||
};
|
||||
|
||||
const buildRangeSettings = (parentElement, settings) => {
|
||||
|
||||
@@ -406,6 +406,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"pyramid_open": {
|
||||
"keyString": "pyramid_open",
|
||||
"friendlyName": "Pyramid Open",
|
||||
"description": "",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"goal": {
|
||||
"keyString": "pyramid_open.goal",
|
||||
"friendlyName": "Goal",
|
||||
"description": "Opens the pyramid if the goal requires you to kill Ganon, unless the goal is Slow Ganon or All Dungeons.",
|
||||
"defaultValue": 50
|
||||
},
|
||||
"auto": {
|
||||
"keyString": "pyramid_open.auto",
|
||||
"friendlyName": "Auto",
|
||||
"description": "Same as Goal, but also opens when any non-dungeon entrance shuffle is used.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"yes": {
|
||||
"keyString": "pyramid_open.yes",
|
||||
"friendlyName": "Always Open",
|
||||
"description": "Pyramid hole is always open. Ganon's vulnerable condition is still required before he can he hurt.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"no": {
|
||||
"keyString": "pyramid_open.no",
|
||||
"friendlyName": "Always Closed",
|
||||
"description": "Pyramid hole is always closed until you defeat Agahnim atop Ganon's Tower.",
|
||||
"defaultValue": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"triforce_pieces_required": {
|
||||
"keyString": "triforce_pieces_required",
|
||||
"friendlyName": "Triforce Pieces Required",
|
||||
@@ -1135,7 +1167,7 @@
|
||||
"beemizer": {
|
||||
"keyString": "beemizer",
|
||||
"friendlyName": "Beemizer",
|
||||
"description": "Remove items from the global item pool and replace them with single bees and bee traps.",
|
||||
"description": "Remove non-health items from the global item pool and replace them with single bees and bee traps.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"0": {
|
||||
@@ -1147,25 +1179,25 @@
|
||||
"1": {
|
||||
"keyString": "beemizer.1",
|
||||
"friendlyName": "Level 1",
|
||||
"description": "25% of the non-essential item pool is replaced with bee traps.",
|
||||
"description": "25% of rupees, bombs and arrows are replaced with bees, of which 60% are traps and 40% single bees",
|
||||
"defaultValue": 1
|
||||
},
|
||||
"2": {
|
||||
"keyString": "beemizer.2",
|
||||
"friendlyName": "Level 2",
|
||||
"description": "60% of the non-essential item pool is replaced with bee traps, of which 20% could be single bees.",
|
||||
"description": "50% of rupees, bombs and arrows are replaced with bees, of which 70% are traps and 30% single bees",
|
||||
"defaultValue": 2
|
||||
},
|
||||
"3": {
|
||||
"keyString": "beemizer.3",
|
||||
"friendlyName": "Level 3",
|
||||
"description": "100% of the non-essential item pool is replaced with bee traps, of which 50% could be single bees.",
|
||||
"description": "75% of rupees, bombs and arrows are replaced with bees, of which 80% are traps and 20% single bees",
|
||||
"defaultValue": 3
|
||||
},
|
||||
"4": {
|
||||
"keyString": "beemizer.4",
|
||||
"friendlyName": "Level 4",
|
||||
"description": "100% of the non-essential item pool is replaced with bee traps.",
|
||||
"description": "100% of rupees, bombs and arrows are replaced with bees, of which 90% are traps and 10% single bees",
|
||||
"defaultValue": 4
|
||||
}
|
||||
}
|
||||
@@ -1250,19 +1282,19 @@
|
||||
"description": "No items are moved",
|
||||
"defaultValue": 50
|
||||
},
|
||||
"1": {
|
||||
"10": {
|
||||
"keyString": "shop_shuffle_slots.10",
|
||||
"friendlyName": "Level 1",
|
||||
"description": "10 Items are moved into shops.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"2": {
|
||||
"20": {
|
||||
"keyString": "shop_shuffle_slots.20",
|
||||
"friendlyName": "Level 2",
|
||||
"description": "20 Items are moved into shops.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"3": {
|
||||
"30": {
|
||||
"keyString": "shop_shuffle_slots.30",
|
||||
"friendlyName": "Level 3",
|
||||
"description": "30 Items are moved into shops.",
|
||||
@@ -1600,6 +1632,25 @@
|
||||
"description": "Hide both of the above options",
|
||||
"defaultValue": 0
|
||||
}
|
||||
},
|
||||
"reduceflashing": {
|
||||
"keyString": "rom.reduceflashing",
|
||||
"friendlyName": "Full-Screen Flashing Effects",
|
||||
"description": "Enable or disable full-screen flashing effects in game.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"on": {
|
||||
"keyString": "rom.reduceflashing.on",
|
||||
"friendlyName": "Disabled",
|
||||
"description": "Disables flashing.",
|
||||
"defaultValue": 50
|
||||
},
|
||||
"off": {
|
||||
"keyString": "rom.reduceflashing.off",
|
||||
"friendlyName": "Enabled",
|
||||
"description": "Enables flashing.",
|
||||
"defaultValue": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"quickswap": {
|
||||
@@ -1797,7 +1848,7 @@
|
||||
"defaultValue": 0
|
||||
},
|
||||
"puke": {
|
||||
"keyString": "rom.ow_palettes.Puke",
|
||||
"keyString": "rom.ow_palettes.puke",
|
||||
"friendlyName": "Puke",
|
||||
"description": "No logic at all.",
|
||||
"defaultValue": 0
|
||||
@@ -1859,7 +1910,7 @@
|
||||
"defaultValue": 0
|
||||
},
|
||||
"puke": {
|
||||
"keyString": "rom.uw_palettes.Puke",
|
||||
"keyString": "rom.uw_palettes.puke",
|
||||
"friendlyName": "Puke",
|
||||
"description": "No logic at all.",
|
||||
"defaultValue": 0
|
||||
@@ -1921,7 +1972,7 @@
|
||||
"defaultValue": 0
|
||||
},
|
||||
"puke": {
|
||||
"keyString": "rom.hud_palettes.Puke",
|
||||
"keyString": "rom.hud_palettes.puke",
|
||||
"friendlyName": "Puke",
|
||||
"description": "No logic at all.",
|
||||
"defaultValue": 0
|
||||
@@ -1983,7 +2034,7 @@
|
||||
"defaultValue": 0
|
||||
},
|
||||
"puke": {
|
||||
"keyString": "rom.shield_palettes.Puke",
|
||||
"keyString": "rom.shield_palettes.puke",
|
||||
"friendlyName": "Puke",
|
||||
"description": "No logic at all.",
|
||||
"defaultValue": 0
|
||||
@@ -2045,7 +2096,7 @@
|
||||
"defaultValue": 0
|
||||
},
|
||||
"puke": {
|
||||
"keyString": "rom.sword_palettes.Puke",
|
||||
"keyString": "rom.sword_palettes.puke",
|
||||
"friendlyName": "Puke",
|
||||
"description": "No logic at all.",
|
||||
"defaultValue": 0
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
# To test if your yaml is valid or not, you can use this website:
|
||||
# http://www.yamllint.com/
|
||||
|
||||
# For use with the weighted-settings page on the website. Changing this value will cause all users to be prompted
|
||||
# to update their settings. The version number should match the current released version number, and the revision
|
||||
# should be updated manually by whoever edits this file.
|
||||
ws_version: 4.0.1 rev1
|
||||
|
||||
description: Template Name # Used to describe your yaml. Useful if you have multiple files
|
||||
name: YourName # Your name in-game. Spaces will be replaced with underscores and there is a 16 character limit
|
||||
### Logic Section ###
|
||||
@@ -97,6 +102,11 @@ goals:
|
||||
ganon_triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then kill Ganon
|
||||
local_ganon_triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout your world, then kill Ganon
|
||||
ice_rod_hunt: 0 # You start with everything needed to 216 the seed. Find the Ice rod, then kill Trinexx at Turtle rock.
|
||||
pyramid_open:
|
||||
goal: 50 # Opens the pyramid if the goal requires you to kill Ganon, unless the goal is Slow Ganon or All Dungeons
|
||||
auto: 0 # Same as Goal, but also opens when any non-dungeon entrance shuffle is used
|
||||
yes: 0 # Pyramid hole is always open. Ganon's vulnerable condition is still required before he can he hurt
|
||||
no: 0 # Pyramid hole is always closed until you defeat Agahnim atop Ganon's Tower
|
||||
triforce_pieces_mode: #Determine how to calculate the extra available triforce pieces.
|
||||
extra: 0 # available = triforce_pieces_extra + triforce_pieces_required
|
||||
percentage: 0 # available = (triforce_pieces_percentage /100) * triforce_pieces_required
|
||||
@@ -218,10 +228,10 @@ pot_shuffle:
|
||||
### End of Enemizer Section ###
|
||||
beemizer: # Remove items from the global item pool and replace them with single bees and bee traps
|
||||
0: 50 # No bee traps are placed
|
||||
1: 0 # 25% of the non-essential item pool is replaced with bee traps
|
||||
2: 0 # 60% of the non-essential item pool is replaced with bee traps, of which 20% could be single bees
|
||||
3: 0 # 100% of the non-essential item pool is replaced with bee traps, of which 50% could be single bees
|
||||
4: 0 # 100% of the non-essential item pool is replaced with bee traps
|
||||
1: 0 # 25% of rupees, bombs and arrows are replaced with bees, of which 60% are traps and 40% single bees
|
||||
2: 0 # 50% of rupees, bombs and arrows are replaced with bees, of which 70% are traps and 30% single bees
|
||||
3: 0 # 75% of rupees, bombs and arrows are replaced with bees, of which 80% are traps and 20% single bees
|
||||
4: 0 # 100% of rupees, bombs and arrows are replaced with bees, of which 90% are traps and 10% single bees
|
||||
### Shop Settings ###
|
||||
shop_shuffle_slots: # Maximum amount of shop slots to be filled with regular item pool items (such as Moon Pearl)
|
||||
0: 50
|
||||
@@ -353,6 +363,9 @@ rom:
|
||||
quickswap: # Enable switching items by pressing the L+R shoulder buttons
|
||||
on: 50
|
||||
off: 0
|
||||
reduceflashing: # Reduces instances of flashing such as lightning attacks, weather, ether and more.
|
||||
on: 50
|
||||
off: 0
|
||||
menuspeed: # Controls how fast the item menu opens and closes
|
||||
normal: 50
|
||||
instant: 0
|
||||
|
||||
@@ -14,6 +14,17 @@ html{
|
||||
color: #eeffeb;
|
||||
}
|
||||
|
||||
#user-warning{
|
||||
display: none;
|
||||
width: calc(100% - 8px);
|
||||
background-color: #ffe86b;
|
||||
border-radius: 4px;
|
||||
color: #000000;
|
||||
padding: 4px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#weighted-settings code{
|
||||
background-color: #d9cd8e;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends 'tablepage.html' %}
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<title>Multiworld Tracker for Room {{ room.id }}</title>
|
||||
<title>Multiworld Tracker</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/tracker.css") }}"/>
|
||||
<script type="application/ecmascript" src="{{ static_autoversion("assets/jquery.scrollsync.js") }}"></script>
|
||||
<script type="application/ecmascript" src="{{ static_autoversion("assets/tracker.js") }}"></script>
|
||||
@@ -151,7 +151,7 @@
|
||||
{% endfor %}
|
||||
{% for team, hints in hints.items() %}
|
||||
<div class="table-wrapper">
|
||||
<table class="table non-unique-item-table">
|
||||
<table class="table non-unique-item-table" data-order='[[5, "asc"], [0, "asc"]]'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Finder</th>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
{% block body %}
|
||||
{% include 'header/grassHeader.html' %}
|
||||
<div id="weighted-settings">
|
||||
<header id="user-warning"></header>
|
||||
<h1>Weighted Settings</h1>
|
||||
<div id="instructions">
|
||||
This page is used to configure your weighted settings. You have three presets you can control, which
|
||||
|
||||
@@ -13,7 +13,7 @@ from Utils import Hint
|
||||
|
||||
|
||||
def get_id(item_name):
|
||||
return Items.item_table[item_name][3]
|
||||
return Items.item_table[item_name][2]
|
||||
|
||||
|
||||
app.jinja_env.filters["location_name"] = lambda location: Regions.lookup_id_to_name.get(location, location)
|
||||
@@ -233,9 +233,9 @@ for item_name, data in Items.item_table.items():
|
||||
if "Key" in item_name:
|
||||
area = item_name.split("(")[1][:-1]
|
||||
if "Small" in item_name:
|
||||
small_key_ids[area] = data[3]
|
||||
small_key_ids[area] = data[2]
|
||||
else:
|
||||
big_key_ids[area] = data[3]
|
||||
big_key_ids[area] = data[2]
|
||||
|
||||
from MultiServer import get_item_name_from_id
|
||||
|
||||
|
||||
Reference in New Issue
Block a user