Nuked the schema file and create my own. Works much better.

This commit is contained in:
Chris Wilson 2020-08-25 20:51:11 -04:00
parent 76f9717c99
commit ad895f045c
5 changed files with 264 additions and 2060 deletions

View File

@ -1,20 +1,8 @@
window.addEventListener('load', () => {
const gameSettings = document.getElementById('game-settings');
new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status !== 200) {
reject("Unable to fetch source yaml file.");
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.yaml` ,true);
ajax.send();
}).then((results) => {
Promise.all([fetchPlayerSettingsYaml(), fetchPlayerSettingsJson()]).then((results) => {
// Load YAML into object
const sourceData = jsyaml.load(results);
const sourceData = jsyaml.safeLoad(results[0], { json: true });
// Update localStorage with three settings objects. Preserve original objects if present.
for (let i=1; i<=3; i++) {
@ -23,19 +11,51 @@ window.addEventListener('load', () => {
localStorage.setItem(`gameSettings${i}`, JSON.stringify(updatedObj));
}
// Build the entire UI
buildUI(JSON.parse(results[1]));
// Populate the UI and add event listeners
populateSettings();
document.getElementById('preset-number').addEventListener('change', populateSettings);
gameSettings.addEventListener('change', handleOptionChange);
gameSettings.addEventListener('keyup', handleOptionChange);
}).catch((error) => {
gameSettings.innerHTML = `
<h2>Something went wrong while loading your game settings page.</h2>
<h2>${error}</h2>
<h2><a href="${window.location.origin}">Click here to return to safety!</a></h2>
`
<h2>Something went wrong while loading your game settings page.</h2>
<h2>${error}</h2>
<h2><a href="${window.location.origin}">Click here to return to safety!</a></h2>
`
});
});
const fetchPlayerSettingsYaml = () => new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status !== 200) {
reject("Unable to fetch source yaml file.");
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.yaml` ,true);
ajax.send();
});
const fetchPlayerSettingsJson = () => new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status !== 200) {
reject('Unable to fetch JSON schema file');
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.json`);
ajax.send();
});
const handleOptionChange = (event) => {
if(!event.target.matches('.setting')) { return; }
const presetNumber = document.getElementById('preset-number').value;
@ -73,7 +93,6 @@ const populateSettings = () => {
settingsInputs.forEach((input) => {
const settingString = input.getAttribute('data-setting');
const settingValue = getSettingValue(settings, settingString);
console.info(`${settingString}: ${settingValue}`);
if(settingValue !== false){
input.value = settingValue;
document.getElementById(settingString).innerText = settingValue;
@ -99,3 +118,98 @@ const getSettingValue = (settings, keyString) => {
});
return currentVal;
};
const buildUI = (settings) => {
const settingsWrapper = document.getElementById('settings-wrapper');
Object.values(settings).forEach((setting) => {
if (typeof(setting.inputType) === 'undefined' || !setting.inputType){
console.error(setting);
throw new Error('Setting with no inputType specified.');
}
switch(setting.inputType){
case 'text':
// Currently, all text input is handled manually because there is very little of it
return;
case 'range':
buildRangeSettings(settingsWrapper, setting);
return;
default:
console.error(setting);
throw new Error('Unhandled inputType specified.');
}
});
};
const buildRangeSettings = (parentElement, settings) => {
// Ensure we are operating on a range-specific setting
if(typeof(settings.inputType) === 'undefined' || settings.inputType !== 'range'){
throw new Error('Invalid input type provided to buildRangeSettings func.');
}
const settingWrapper = document.createElement('div');
settingWrapper.className = 'setting-wrapper';
if(typeof(settings.friendlyName) !== 'undefined' && settings.friendlyName){
const sectionTitle = document.createElement('span');
sectionTitle.className = 'title-span';
sectionTitle.innerText = settings.friendlyName;
settingWrapper.appendChild(sectionTitle);
}
if(settings.description){
const description = document.createElement('span');
description.className = 'description-span';
description.innerText = settings.description;
settingWrapper.appendChild(description);
}
// Create table
const optionSetTable = document.createElement('table');
optionSetTable.className = 'option-set';
// Create table body
const tbody = document.createElement('tbody');
Object.keys(settings.subOptions).forEach((setting) => {
// Overwrite setting key name with real object
setting = settings.subOptions[setting];
const settingId = (Math.random() * 1000000).toString();
// Create rows for each option
const optionRow = document.createElement('tr');
// Option name td
const optionName = document.createElement('td');
optionName.className = 'option-name';
const optionLabel = document.createElement('label');
optionLabel.setAttribute('for', settingId);
optionLabel.innerText = setting.friendlyName;
optionName.appendChild(optionLabel);
optionRow.appendChild(optionName);
// Option value td
const optionValue = document.createElement('td');
optionValue.className = 'option-value';
const input = document.createElement('input');
input.className = 'setting';
input.setAttribute('id', settingId);
input.setAttribute('type', 'range');
input.setAttribute('min', '0');
input.setAttribute('max', '100');
input.setAttribute('data-setting', setting.keyString);
input.value = setting.defaultValue;
optionValue.appendChild(input);
const valueDisplay = document.createElement('span');
valueDisplay.setAttribute('id', setting.keyString);
valueDisplay.innerText = setting.defaultValue;
optionValue.appendChild(valueDisplay);
optionRow.appendChild(optionValue);
tbody.appendChild(optionRow);
});
optionSetTable.appendChild(tbody);
settingWrapper.appendChild(optionSetTable);
parentElement.appendChild(settingWrapper);
};
const buildSelectSettings = (parentElement, settings) => {};

View File

@ -0,0 +1,88 @@
{
"description": {
"keyString": "description",
"friendlyName": "Description",
"inputType": "text",
"description": "A short description of this preset. Useful if you have multiple files",
"defaultValue": "Preset Name"
},
"name": {
"keyString": "name",
"friendlyName": "Player Name",
"inputType": "text",
"description": "Displayed in-game. Spaces will be replaced with underscores.",
"defaultValue": "Your Name"
},
"glitches_required": {
"keyString": "glitches_required",
"friendlyName": "Glitches Required",
"description": "Determine the logic required to complete the seed.",
"inputType": "range",
"subOptions": {
"none": {
"keyString": "glitches_required.none",
"friendlyName": "None",
"description": "No glitches required.",
"defaultValue": 50
},
"minor_glitches": {
"keyString": "glitches_required.minor_glitches",
"friendlyName": "Minor Glitches",
"description": "Puts fake flipper, water-walk, super bunny, etc into logic",
"defaultValue": 0
},
"overworld_glitches": {
"keyString": "glitches_required.overworld_glitches",
"friendlyName": "Overworld Glitches",
"description": "Assumes the player has knowledge of both overworld major glitches (boots clips, mirror clips) and minor glitches (fake flipper, super bunny shenanigans, water walk and etc.)",
"defaultValue": 0
},
"no_logic": {
"keyString": "glitches_required.no_logic",
"friendlyName": "No Logic",
"description": "Your items are placed with no regard to any logic. Your Fire Rod could be on your Trinexx.",
"defaultValue": 0
}
}
},
"map_shuffle": {
"keyString": "map_shuffle",
"friendlyName": "Map Shuffle",
"description": "Shuffle dungeon maps into the world and other dungeons, including other players' worlds.",
"inputType": "range",
"subOptions": {
"off": {
"keyString": "map_shuffle.off",
"friendlyName": "Off",
"description": "Disable map shuffle.",
"defaultValue": 50
},
"on": {
"keyString": "map_shuffle.on",
"friendlyName": "On",
"description": "Enable map shuffle.",
"defaultValue": 0
}
}
},
"compass_shuffle": {
"keyString": "compass_shuffle",
"friendlyName": "Compass Shuffle",
"description": "Shuffle compasses into the world and other dungeons, including other players' worlds",
"inputType": "range",
"subOptions": {
"off": {
"keyString": "compass_shuffle.off",
"friendlyName": "Off",
"description": "Disable compass shuffle.",
"defaultValue": 50
},
"on": {
"keyString": "compass_shuffle.on",
"friendlyName": "On",
"description": "Enable compass shuffle.",
"defaultValue": 0
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,19 @@
padding-right: 0.25rem;
}
#game-settings #instructions{
text-align: center;
#game-settings .instructions{
text-align: left;
}
#game-settings #settings-wrapper .setting-wrapper{
display: flex;
flex-direction: column;
justify-content: flex-start;
width: 100%;
}
#game-settings #settings-wrapper .setting-wrapper .title-span{
font-weight: bold;
}
#game-settings #settings-wrapper{

View File

@ -9,40 +9,42 @@
{% block body %}
<div id="game-settings" class="main-content">
<h3>Game Settings</h3>
<h3>Player Settings</h3>
<div id="instructions">
This page is used to configure your game settings. You have three presets you can control, which
This page is used to configure your player settings. You have three presets you can control, which
you can access using the dropdown menu below. These settings will be usable when generating a
single player game, or you can export them to a <code>.yaml</code> file and use them in a multiworld.
</div>
<div id="settings-wrapper">
Choose a preset and optionally assign it a nickname, which will be used as the file's description if
you download it.
<table class="option-set">
<tbody>
<tr>
<td class="option-name">
<label for="preset-number">Preset Number:</label>
</td>
<td class="option-value">
<select id="preset-number">
<option value="1">Preset 1</option>
<option value="2">Preset 2</option>
<option value="3">Preset 3</option>
</select>
</td>
</tr>
<tr>
<td class="option-name">
<label for="description">Preset Name:</label>
</td>
<td class="option-value">
<input id="description" class="setting" data-setting="description" />
</td>
</tr>
</tbody>
</table>
<div class="setting-wrapper">
Choose a preset and optionally assign it a nickname, which will be used as the file's description if
you download it.
<table class="option-set">
<tbody>
<tr>
<td class="option-name">
<label for="preset-number">Preset Number:</label>
</td>
<td class="option-value">
<select id="preset-number">
<option value="1">Preset 1</option>
<option value="2">Preset 2</option>
<option value="3">Preset 3</option>
</select>
</td>
</tr>
<tr>
<td class="option-name">
<label for="description">Preset Name:</label>
</td>
<td class="option-value">
<input id="description" class="setting" data-setting="description" />
</td>
</tr>
</tbody>
</table>
</div>
Choose a name you want to represent you in-game. This will appear when you send items
to other people in multiworld games.
@ -58,73 +60,6 @@
</tr>
</tbody>
</table>
Glitches Required - Allows the generator to place required items in locations which require knowledge
of glitches.
<table class="option-set">
<tbody>
<tr>
<td class="option-name">
<label for="glitches-required-none">None:</label>
</td>
<td class="option-value">
<input id="glitches-required-none"
data-setting="glitches_required.none"
class="setting"
type="range"
min="0"
max="100"
/>
<span id="glitches_required.none"></span>
</td>
</tr>
<tr>
<td class="option-name">
<label for="glitches-required-minor">Minor Glitches:</label>
</td>
<td class="option-value">
<input id="glitches-required-minor"
data-setting="glitches_required.minor_glitches"
class="setting"
type="range"
min="0"
max="100"
/>
<span id="glitches_required.minor_glitches"></span>
</td>
</tr>
<tr>
<td class="option-name">
<label for="glitches-required-overworld">Overworld Glitches:</label>
</td>
<td class="option-value">
<input id="glitches-required-overworld"
data-setting="glitches_required.overworld_glitches"
class="setting"
type="range"
min="0"
max="100"
/>
<span id="glitches_required.overworld_glitches"></span>
</td>
</tr>
<tr>
<td class="option-name">
<label for="glitches-required-no-logic">No Logic:</label>
</td>
<td class="option-value">
<input id="glitches-required-no-logic"
data-setting="glitches_required.no_logic"
class="setting"
type="range"
min="0"
max="100"
/>
<span id="glitches_required.no_logic"></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endblock %}