Add simpler Player Settings page
This commit is contained in:
parent
da6c44a1cf
commit
71209a962a
WebHostLib
static
templates
|
@ -2,7 +2,14 @@ window.addEventListener('load', () => {
|
|||
fetchSettingData().then((settingData) => {
|
||||
createDefaultSettings(settingData);
|
||||
buildUI(settingData);
|
||||
populateSettings();
|
||||
document.getElementById('export-settings').addEventListener('click', () => exportSettings());
|
||||
document.getElementById('generate-race').addEventListener('click', () => generateGame(true))
|
||||
document.getElementById('generate-game').addEventListener('click', () => generateGame());
|
||||
|
||||
const playerSettings = JSON.parse(localStorage.getItem('playerSettings'));
|
||||
const nameInput = document.getElementById('player-name');
|
||||
nameInput.addEventListener('keyup', (event) => updateSetting(event));
|
||||
nameInput.value = playerSettings.name;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -17,7 +24,7 @@ const fetchSettingData = () => new Promise((resolve, reject) => {
|
|||
try{ resolve(JSON.parse(ajax.responseText)); }
|
||||
catch(error){ reject(error); }
|
||||
};
|
||||
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.json` ,true);
|
||||
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.json`, true);
|
||||
ajax.send();
|
||||
});
|
||||
|
||||
|
@ -27,6 +34,9 @@ const createDefaultSettings = (settingData) => {
|
|||
for (let roSetting of Object.keys(settingData.readOnly)){
|
||||
newSettings[roSetting] = settingData.readOnly[roSetting];
|
||||
}
|
||||
for (let generalOption of Object.keys(settingData.generalOptions)){
|
||||
newSettings[generalOption] = settingData.generalOptions[generalOption];
|
||||
}
|
||||
for (let gameOption of Object.keys(settingData.gameOptions)){
|
||||
newSettings[gameOption] = settingData.gameOptions[gameOption].defaultValue;
|
||||
}
|
||||
|
@ -42,7 +52,7 @@ const buildUI = (settingData) => {
|
|||
const leftGameOpts = {};
|
||||
const rightGameOpts = {};
|
||||
Object.keys(settingData.gameOptions).forEach((key, index) => {
|
||||
if (index % 2 === 0) { leftGameOpts[key] = settingData.gameOptions[key]; }
|
||||
if (index < Object.keys(settingData.gameOptions).length / 2) { leftGameOpts[key] = settingData.gameOptions[key]; }
|
||||
else { rightGameOpts[key] = settingData.gameOptions[key]; }
|
||||
});
|
||||
document.getElementById('game-options-left').appendChild(buildOptionsTable(leftGameOpts));
|
||||
|
@ -52,7 +62,7 @@ const buildUI = (settingData) => {
|
|||
const leftRomOpts = {};
|
||||
const rightRomOpts = {};
|
||||
Object.keys(settingData.romOptions).forEach((key, index) => {
|
||||
if (index % 2 === 0) { leftRomOpts[key] = settingData.romOptions[key]; }
|
||||
if (index < Object.keys(settingData.romOptions).length / 2) { leftRomOpts[key] = settingData.romOptions[key]; }
|
||||
else { rightRomOpts[key] = settingData.romOptions[key]; }
|
||||
});
|
||||
document.getElementById('rom-options-left').appendChild(buildOptionsTable(leftRomOpts));
|
||||
|
@ -60,6 +70,7 @@ const buildUI = (settingData) => {
|
|||
};
|
||||
|
||||
const buildOptionsTable = (settings) => {
|
||||
const currentSettings = JSON.parse(localStorage.getItem('playerSettings'));
|
||||
const table = document.createElement('table');
|
||||
const tbody = document.createElement('tbody');
|
||||
|
||||
|
@ -78,12 +89,18 @@ const buildOptionsTable = (settings) => {
|
|||
// td Right
|
||||
const tdr = document.createElement('td');
|
||||
const select = document.createElement('select');
|
||||
select.setAttribute('data-key', setting);
|
||||
settings[setting].options.forEach((opt) => {
|
||||
const option = document.createElement('option');
|
||||
option.setAttribute('value', opt.value);
|
||||
option.innerText = opt.name;
|
||||
if ((isNaN(currentSettings[setting]) && (parseInt(opt.value, 10) === parseInt(currentSettings[setting]))) ||
|
||||
(opt.value === currentSettings[setting])) {
|
||||
option.selected = true;
|
||||
}
|
||||
select.appendChild(option);
|
||||
});
|
||||
select.addEventListener('change', (event) => updateSetting(event));
|
||||
tdr.appendChild(select);
|
||||
tr.appendChild(tdr);
|
||||
tbody.appendChild(tr);
|
||||
|
@ -93,12 +110,37 @@ const buildOptionsTable = (settings) => {
|
|||
return table;
|
||||
};
|
||||
|
||||
const populateSettings = () => {
|
||||
// TODO
|
||||
};
|
||||
|
||||
const updateSetting = (key, setting) => {
|
||||
const updateSetting = (event) => {
|
||||
console.log(event.target.value);
|
||||
const options = JSON.parse(localStorage.getItem('playerSettings'));
|
||||
options[key] = setting;
|
||||
options[event.target.getAttribute('data-key')] = isNaN(event.target.value) ?
|
||||
event.target.value : parseInt(event.target.value, 10);
|
||||
localStorage.setItem('playerSettings', JSON.stringify(options));
|
||||
};
|
||||
|
||||
const exportSettings = () => {
|
||||
const settings = JSON.parse(localStorage.getItem('playerSettings'));
|
||||
if (!settings.name || settings.name.trim().length === 0) { settings.name = "noname"; }
|
||||
const yamlText = jsyaml.safeDump(settings, { noCompatMode: true }).replaceAll(/'(\d+)':/g, (x, y) => `${y}:`);
|
||||
download(`${document.getElementById('player-name').value}.yaml`, yamlText);
|
||||
};
|
||||
|
||||
/** Create an anchor and trigger a download of a text file. */
|
||||
const download = (filename, text) => {
|
||||
const downloadLink = document.createElement('a');
|
||||
downloadLink.setAttribute('href','data:text/yaml;charset=utf-8,'+ encodeURIComponent(text))
|
||||
downloadLink.setAttribute('download', filename);
|
||||
downloadLink.style.display = 'none';
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
};
|
||||
|
||||
const generateGame = (raceMode = false) => {
|
||||
axios.post('/api/generate', {
|
||||
weights: { player: localStorage.getItem('playerSettings') },
|
||||
presetData: { player: localStorage.getItem('playerSettings') },
|
||||
playerCount: 1,
|
||||
race: raceMode ? '1' : '0',
|
||||
});
|
||||
};
|
||||
|
|
|
@ -12,78 +12,54 @@
|
|||
"debug": "off"
|
||||
},
|
||||
"generalOptions": {
|
||||
"name": "Player"
|
||||
"name": "PlayerName"
|
||||
},
|
||||
"gameOptions": {
|
||||
"glitches_required":{
|
||||
"type": "select",
|
||||
"friendlyName": "Glitches Required",
|
||||
"description": "Choose which glitches will be considered in-logic",
|
||||
"defaultValue": "none",
|
||||
"options": [
|
||||
{
|
||||
"name": "None",
|
||||
"value": "none"
|
||||
},
|
||||
{
|
||||
"name": "Minor Glitches",
|
||||
"value": "minor_glitches"
|
||||
},
|
||||
{
|
||||
"name": "Overworld Glitches",
|
||||
"value": "overworld_glitches"
|
||||
},
|
||||
{
|
||||
"name": "No Logic",
|
||||
"value": "no_logic"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dark_room_logic": {
|
||||
"goals": {
|
||||
"type": "select",
|
||||
"friendlyName": "Dark Room Logic",
|
||||
"description": "Choose your logical access to dark rooms",
|
||||
"defaultValue": "lamp",
|
||||
"friendlyName": "Goal",
|
||||
"description": "Choose the condition for winning the game",
|
||||
"defaultValue": "ganon",
|
||||
"options": [
|
||||
{
|
||||
"name": "Lamp Required",
|
||||
"value": "lamp"
|
||||
"name": "Kill Ganon",
|
||||
"value": "ganon"
|
||||
},
|
||||
{
|
||||
"name": "Torches Lightable",
|
||||
"value": "torches"
|
||||
"name": "Fast Ganon (Pyramid Always Open)",
|
||||
"value": "fast_ganon"
|
||||
},
|
||||
{
|
||||
"name": "Always In-Logic",
|
||||
"value": "none"
|
||||
"name": "All Dungeons",
|
||||
"value": "dungeons"
|
||||
},
|
||||
{
|
||||
"name": "Master Sword Pedestal",
|
||||
"value": "pedestal"
|
||||
},
|
||||
{
|
||||
"name": "Triforce Hunt",
|
||||
"value": "triforce_hunt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dungeon_items": {
|
||||
"mode": {
|
||||
"type": "select",
|
||||
"friendlyName": "Dungeon Item Shuffle",
|
||||
"description": "Choose which dungeon items you want shuffled",
|
||||
"defaultValue": "none",
|
||||
"friendlyName": "World State",
|
||||
"description": "Choose the state of the game world",
|
||||
"defaultValue": "standard",
|
||||
"options": [
|
||||
{
|
||||
"name": "None",
|
||||
"value": "none"
|
||||
"name": "Standard",
|
||||
"value": "standard"
|
||||
},
|
||||
{
|
||||
"name": "Map & Compass",
|
||||
"value": "mc"
|
||||
"name": "Open",
|
||||
"value": "open"
|
||||
},
|
||||
{
|
||||
"name": "Small Keys Only",
|
||||
"value": "s"
|
||||
},
|
||||
{
|
||||
"name": "Big Keys Only",
|
||||
"value": "b"
|
||||
},
|
||||
{
|
||||
"name": "Full Keysanity",
|
||||
"value": "mscb"
|
||||
"name": "Inverted",
|
||||
"value": "inverted"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -127,74 +103,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"entrance_shuffle": {
|
||||
"type": "select",
|
||||
"friendlyName": "Entrance Shuffle",
|
||||
"description": "Shuffles the game map. Not recommended for beginners",
|
||||
"defaultValue": "none",
|
||||
"options": [
|
||||
{
|
||||
"name": "None",
|
||||
"value": "none"
|
||||
},
|
||||
{
|
||||
"name": "Dungeon Entrances",
|
||||
"value": "dungeonssimple"
|
||||
},
|
||||
{
|
||||
"name": "Dungeon Interiors",
|
||||
"value": "dungeonsfull"
|
||||
},
|
||||
{
|
||||
"name": "Simple Entrances",
|
||||
"value": "simple"
|
||||
},
|
||||
{
|
||||
"name": "Restricted",
|
||||
"value": "restricted"
|
||||
},
|
||||
{
|
||||
"name": "Full Shuffle",
|
||||
"value": "full"
|
||||
},
|
||||
{
|
||||
"name": "Crossed Shuffle",
|
||||
"value": "crossed"
|
||||
},
|
||||
{
|
||||
"name": "Insanity Shuffle",
|
||||
"value": "insanity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"goals": {
|
||||
"type": "select",
|
||||
"friendlyName": "Goal",
|
||||
"description": "Choose the condition for winning the game",
|
||||
"defaultValue": "ganon",
|
||||
"options": [
|
||||
{
|
||||
"name": "Kill Ganon",
|
||||
"value": "ganon"
|
||||
},
|
||||
{
|
||||
"name": "Fast Ganon (Pyramid Always Open)",
|
||||
"value": "fast_ganon"
|
||||
},
|
||||
{
|
||||
"name": "All Dungeons",
|
||||
"value": "dungeons"
|
||||
},
|
||||
{
|
||||
"name": "Master Sword Pedestal",
|
||||
"value": "pedestal"
|
||||
},
|
||||
{
|
||||
"name": "Triforce Hunt",
|
||||
"value": "triforce_hunt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tower_open": {
|
||||
"type": "select",
|
||||
"friendlyName": "Ganon's Tower Access",
|
||||
|
@ -283,26 +191,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"mode": {
|
||||
"type": "select",
|
||||
"friendlyName": "World State",
|
||||
"description": "Choose the state of the game world",
|
||||
"defaultValue": "standard",
|
||||
"options": [
|
||||
{
|
||||
"name": "Standard",
|
||||
"value": "standard"
|
||||
},
|
||||
{
|
||||
"name": "Open",
|
||||
"value": "open"
|
||||
},
|
||||
{
|
||||
"name": "Inverted",
|
||||
"value": "inverted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"retro": {
|
||||
"type": "select",
|
||||
"friendlyName": "Retro Mode",
|
||||
|
@ -316,14 +204,6 @@
|
|||
{
|
||||
"name": "Enabled",
|
||||
"value": "on"
|
||||
},
|
||||
{
|
||||
"name": "Classic (Universal Small Keys)",
|
||||
"value": null,
|
||||
"overrides": {
|
||||
"retro": "on",
|
||||
"dungeon_items": "+u"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -367,6 +247,122 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"glitches_required":{
|
||||
"type": "select",
|
||||
"friendlyName": "Glitches Required",
|
||||
"description": "Choose which glitches will be considered in-logic",
|
||||
"defaultValue": "none",
|
||||
"options": [
|
||||
{
|
||||
"name": "None",
|
||||
"value": "none"
|
||||
},
|
||||
{
|
||||
"name": "Minor Glitches",
|
||||
"value": "minor_glitches"
|
||||
},
|
||||
{
|
||||
"name": "Overworld Glitches",
|
||||
"value": "overworld_glitches"
|
||||
},
|
||||
{
|
||||
"name": "No Logic",
|
||||
"value": "no_logic"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dark_room_logic": {
|
||||
"type": "select",
|
||||
"friendlyName": "Dark Room Logic",
|
||||
"description": "Choose your logical access to dark rooms",
|
||||
"defaultValue": "lamp",
|
||||
"options": [
|
||||
{
|
||||
"name": "Lamp Required",
|
||||
"value": "lamp"
|
||||
},
|
||||
{
|
||||
"name": "Torches Lightable",
|
||||
"value": "torches"
|
||||
},
|
||||
{
|
||||
"name": "Always In-Logic",
|
||||
"value": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dungeon_items": {
|
||||
"type": "select",
|
||||
"friendlyName": "Dungeon Item Shuffle",
|
||||
"description": "Choose which dungeon items you want shuffled",
|
||||
"defaultValue": "none",
|
||||
"options": [
|
||||
{
|
||||
"name": "None",
|
||||
"value": "none"
|
||||
},
|
||||
{
|
||||
"name": "Map & Compass",
|
||||
"value": "mc"
|
||||
},
|
||||
{
|
||||
"name": "Small Keys Only",
|
||||
"value": "s"
|
||||
},
|
||||
{
|
||||
"name": "Big Keys Only",
|
||||
"value": "b"
|
||||
},
|
||||
{
|
||||
"name": "Full Keysanity",
|
||||
"value": "mscb"
|
||||
},
|
||||
{
|
||||
"name": "Universal Small Keys",
|
||||
"value": "u"
|
||||
}
|
||||
]
|
||||
},
|
||||
"entrance_shuffle": {
|
||||
"type": "select",
|
||||
"friendlyName": "Entrance Shuffle",
|
||||
"description": "Shuffles the game map. Not recommended for beginners",
|
||||
"defaultValue": "none",
|
||||
"options": [
|
||||
{
|
||||
"name": "None",
|
||||
"value": "none"
|
||||
},
|
||||
{
|
||||
"name": "Dungeon Entrances",
|
||||
"value": "dungeonssimple"
|
||||
},
|
||||
{
|
||||
"name": "Dungeon Interiors",
|
||||
"value": "dungeonsfull"
|
||||
},
|
||||
{
|
||||
"name": "Simple Entrances",
|
||||
"value": "simple"
|
||||
},
|
||||
{
|
||||
"name": "Restricted",
|
||||
"value": "restricted"
|
||||
},
|
||||
{
|
||||
"name": "Full Shuffle",
|
||||
"value": "full"
|
||||
},
|
||||
{
|
||||
"name": "Crossed Shuffle",
|
||||
"value": "crossed"
|
||||
},
|
||||
{
|
||||
"name": "Insanity Shuffle",
|
||||
"value": "insanity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"item_pool": {
|
||||
"type": "select",
|
||||
"friendlyName": "Item Pool",
|
||||
|
@ -549,34 +545,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"heartcolor": {
|
||||
"type": "select",
|
||||
"friendlyName": "Heart Color",
|
||||
"description": "Change the color of your hearts in-game",
|
||||
"defaultValue": "red",
|
||||
"options": [
|
||||
{
|
||||
"name": "Red",
|
||||
"value": "red"
|
||||
},
|
||||
{
|
||||
"name": "Blue",
|
||||
"value": "blue"
|
||||
},
|
||||
{
|
||||
"name": "Green",
|
||||
"value": "green"
|
||||
},
|
||||
{
|
||||
"name": "Yellow",
|
||||
"value": "yellow"
|
||||
},
|
||||
{
|
||||
"name": "Random",
|
||||
"value": "random"
|
||||
}
|
||||
]
|
||||
},
|
||||
"heartbeep": {
|
||||
"type": "select",
|
||||
"friendlyName": "Heart-Beep Speed",
|
||||
|
@ -605,6 +573,34 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"heartcolor": {
|
||||
"type": "select",
|
||||
"friendlyName": "Heart Color",
|
||||
"description": "Change the color of your hearts in-game",
|
||||
"defaultValue": "red",
|
||||
"options": [
|
||||
{
|
||||
"name": "Red",
|
||||
"value": "red"
|
||||
},
|
||||
{
|
||||
"name": "Blue",
|
||||
"value": "blue"
|
||||
},
|
||||
{
|
||||
"name": "Green",
|
||||
"value": "green"
|
||||
},
|
||||
{
|
||||
"name": "Yellow",
|
||||
"value": "yellow"
|
||||
},
|
||||
{
|
||||
"name": "Random",
|
||||
"value": "random"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ow_palettes": {
|
||||
"type": "select",
|
||||
"friendlyName": "Overworld Palette",
|
||||
|
|
|
@ -14,6 +14,13 @@ html{
|
|||
color: #eeffeb;
|
||||
}
|
||||
|
||||
#player-settings #player-settings-button-row{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#player-settings code{
|
||||
background-color: #d9cd8e;
|
||||
border-radius: 4px;
|
||||
|
@ -71,7 +78,7 @@ html{
|
|||
flex-direction: row;
|
||||
}
|
||||
|
||||
#player-settings .left, #game-options .right{
|
||||
#player-settings .left, #player-settings .right{
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
@ -80,7 +87,10 @@ html{
|
|||
}
|
||||
|
||||
#player-settings table label{
|
||||
display: block;
|
||||
min-width: 200px;
|
||||
margin-right: 4px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
@media all and (max-width: 1000px){
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
{% block head %}
|
||||
<title>Player Settings</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/playerSettings.css") }}" />
|
||||
<script type="application/ecmascript" src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script type="application/ecmascript" src="{{ static_autoversion("assets/js-yaml.min.js") }}"></script>
|
||||
<script type="application/ecmascript" src="{{ static_autoversion("assets/playerSettings.js") }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -17,7 +19,7 @@
|
|||
|
||||
<p><label for="player-name">Please enter your player name. This will appear in-game as you send and receive
|
||||
items, if you are playing in a MultiWorld.</label><br />
|
||||
<input id="player-name" placeholder="Player Name" />
|
||||
<input id="player-name" placeholder="Player Name" data-key="name" maxlength="16" />
|
||||
</p>
|
||||
|
||||
<h2>Game Options</h2>
|
||||
|
@ -31,5 +33,11 @@
|
|||
<div id="rom-options-left" class="left"></div>
|
||||
<div id="rom-options-right" class="right"></div>
|
||||
</div>
|
||||
|
||||
<div id="player-settings-button-row">
|
||||
<button id="export-settings">Export Settings</button>
|
||||
<button id="generate-game">Generate Game</button>
|
||||
<button id="generate-race">Generate Race</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue