Merge branch 'main' into breaking_changes
# Conflicts: # MultiClient.py # Utils.py # worlds/alttp/ItemPool.py # worlds/alttp/Main.py # worlds/alttp/Shops.py
This commit is contained in:
@@ -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.",
|
||||
|
||||
@@ -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 rev0
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,7 +11,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)
|
||||
@@ -231,9 +231,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